简体   繁体   English

如何在 Scala 中进行依赖注入?

[英]How would one do dependency injection in scala?

I'm still at the beginning in learning scala in addition to java and i didn't get it how is one supposed to do DI there?除了java之外,我还在学习scala的开始,我不明白应该如何在那里做DI? can or should i use an existing DI library, should it be done manually or is there another way?我可以或应该使用现有的 DI 库,应该手动完成还是有其他方法?

标准 Java DI 框架通常与 Scala 一起使用,但您也可以使用语言结构来实现相同的效果,而无需外部依赖。

A new dependency injection library specifically for Scala is Dick Wall's SubCut .一个专门用于 Scala 的新依赖注入库是 Dick Wall 的SubCut

Whereas the Jonas Bonér article referenced in Dan Story's answer emphasizes compile-time bound instances and static injection (via mix-ins), SubCut is based on runtime initialization of immutable modules, and dynamic injection by querying the bound modules by type, string names, or scala.Symbol names. Dan Story 的回答中引用的 Jonas Bonér 文章强调了编译时绑定实例和静态注入(通过混入),而 SubCut 基于不可变模块的运行时初始化,以及通过按类型、字符串名称查询绑定模块的动态注入,或 scala.Symbol 名称。

You can read more about the comparison with the Cake pattern in the GettingStarted document.您可以在GettingStarted文档中阅读有关与 Cake 模式比较的更多信息。

Dependency Injection itself can be done without any tool, framework or container support.依赖注入本身可以在没有任何工具、框架或容器支持的情况下完成。 You only need to remove new s from your code and move them to constructors.您只需要从代码中删除new并将它们移动到构造函数中。 The one tedious part that remains is wiring the objects at "the end of the world", where containers help a lot.剩下的一个乏味的部分是在“世界的尽头”连接对象,容器在那里有很大帮助。

Though with Scala's 2.10 macros, you can generate the wiring code at compile-time and have auto-wiring and type-safety.尽管使用 Scala 的 2.10 宏,您可以在编译时生成接线代码并具有自动接线和类型安全性。

See the Dependency Injection in Scala Guide参见Scala 指南中依赖注入

A recent project illustrates a DI based purely on constructor injection: zalando/grafter最近的一个项目说明了一个纯粹基于构造函数注入的 DI: zalando/grafter

What's wrong with constructor injection again?构造函数注入又出了什么问题?

There are many libraries or approaches for doing dependency injection in Scala.在 Scala 中有许多方法可用于进行依赖注入 Grafter goes back to the fundamentals of dependency injection by just using constructor injection : no reflection, no xml, no annotations, no inheritance or self-types. Gratter仅使用构造函数注入就可以追溯到依赖注入的基础:没有反射、没有 xml、没有注释、没有继承或自类型。

Then, Grafter add to constructor injection just the necessary support to:然后,Grafter 添加到构造函数注入只是必要的支持:

  • instantiate a component-based application from a configuration从配置实例化基于组件的应用程序
  • fine-tune the wiring (create singletons)微调接线(创建单例)
  • test the application by replacing components通过更换组件来测试应用程序
  • start / stop the application启动/停止应用程序

Grafter is targeting every possible application because it focuses on associating just 3 ideas: Gratter 的目标是所有可能的应用程序,因为它只专注于关联 3 个想法:

  • case classes and interfaces for components组件的案例类和接口
  • Reader instances and shapeless for the configuration读取器实例和配置的无形
  • tree rewriting and kiama for everything else!树重写和 kiama 为其他一切!

我自己没有这样做,但大多数 DI 框架都在字节码级别 (AFAIK) 工作,因此应该可以将它们与任何 JVM 语言一起使用。

Previous posts covered the techniques.以前的帖子涵盖了这些技术。 I wanted to add a link to Martin Odersky's May 2014 talk on the Scala language objectives.我想添加一个指向 Martin Odersky 2014 年 5 月关于 Scala 语言目标的演讲的链接。 He identifies languages that "require" a DI container to inject dependencies as poorly implemented.他认为“需要”DI 容器来注入依赖项的语言实现得很差。 I agree with this personally, but it is only an opinion.我个人同意这一点,但这只是一种意见。 It does seem to indicate that including a DI dependency in your Scala project is non-idiomatic, but again this is opinion.这似乎表明在您的 Scala 项目中包含 DI 依赖项是不惯用的,但这又是一种意见。 Practically speaking, even with a language designed to inject dependencies natively, there is a certain amount of consistency gained by using a container.实际上,即使使用旨在本地注入依赖项的语言,也可以通过使用容器获得一定程度的一致性。 It is worth considering both points of view for your purposes.出于您的目的,值得考虑这两种观点。

https://youtu.be/ecekSCX3B4Q?t=1154 https://youtu.be/ecekSCX3B4Q?t=1154

I would suggest you to try distage (disclaimer: I'm the author).我建议你尝试disstage (免责声明:我是作者)。

It allows you to do much more than a typical DI does and has many unique traits :它允许您做的比典型的 DI 做的更多,并且具有许多独特的特征

  1. distage supports multiple configurations (eg you may run your app with different sets of component implementations), disstage 支持多种配置(例如,您可以使用不同的组件实现集运行您的应用程序),
  2. distage allows you to correctly share dependencies across your tests and easily run same tests for different implementations of your components, disstage 允许您在测试之间正确共享依赖项,并轻松地组件的不同实现运行相同的测试
  3. distage supports roles so you may run multiple services within the same process sharing dependencies between them, disstage 支持 角色,因此您可以在同一进程中运行多个服务,共享它们之间的依赖关系,
  4. distage does not depend on scala-reflect (but supports all the necessary features of Scala typesystem, like higher-kinded types). disstage 不依赖于scala-reflect (但支持 Scala 类型系统的所有必要特性,如高级类型)。

You may also watch our talk at Functional Scala 2019 where we've discussed and demonstrated some important capabiliteis of distage.您还可以观看我们在 Functional Scala 2019上的演讲,我们在那里讨论并展示了一些重要的 disstage 能力。

In addition to the answer of Dan Story, I blogged about a DI variant that also uses language constructs only but is not mentioned in Jonas's post: Value Injection on Traits (linking to web.archive.org now).除了 Dan Story 的回答之外,我还写了一篇关于 DI 变体的博客,该变体也仅使用语言结构,但在 Jonas 的帖子中未提及:特征值注入(现在链接到 web.archive.org)。 This pattern is working very well for me.这种模式对我来说效果很好。

我在这里展示了如何使用 2.10 在 Scala 中创建一个非常简单的功能性 DI 容器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM