如何在 Scala 中进行依赖注入?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2563929/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How would one do dependency injection in scala?
提问by Fabian
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? can or should i use an existing DI library, should it be done manually or is there another way?
除了java之外,我还在学习scala的开始,我不明白应该如何在那里做DI?我可以或应该使用现有的 DI 库,应该手动完成还是有其他方法?
采纳答案by Dan Story
Standard Java DI frameworks will usually work with Scala, but you can also use language constructs to achieve the same effectwithout external dependencies.
标准 Java DI 框架通常与 Scala 一起使用,但您也可以使用语言结构来实现相同的效果,而无需外部依赖。
回答by Allan Erskine
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 GettingStarteddocument.
您可以在GettingStarted文档中阅读有关与 Cake 模式比较的更多信息。
回答by adamw
Dependency Injection itself can be done without any tool, framework or container support. You only need to remove news from your code and move them to constructors. The one tedious part that remains is wiring the objects at "the end of the world", where containers help a lot.
依赖注入本身可以在没有任何工具、框架或容器支持的情况下完成。您只需new要从代码中删除s 并将它们移动到构造函数中。剩下的一个乏味的部分是在“世界的尽头”连接对象,容器在那里有很大帮助。
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 宏,您可以在编译时生成接线代码并具有自动接线和类型安全性。
回答by VonC
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 manylibrariesor approachesfor doing dependency injectionin 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.
Then, Grafter add to constructor injection just the necessary support to:
- 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:
- case classes and interfaces for components
- Reader instances and shapeless for the configuration
- tree rewriting and kiama for everything else!
构造函数注入又出了什么问题?
在 Scala 中有许多库或方法可用于进行依赖注入。Gratter仅使用构造函数注入就可以追溯到依赖注入的基础:没有反射、没有 xml、没有注释、没有继承或自类型。
然后,Grafter 添加到构造函数注入只是必要的支持:
- 从配置实例化基于组件的应用程序
- 微调接线(创建单例)
- 通过更换组件来测试应用程序
- 启动/停止应用程序
Gratter 的目标是所有可能的应用程序,因为它只专注于关联 3 个想法:
- 组件的案例类和接口
- 读取器实例和配置的无形
- 树重写和 kiama 为其他一切!
回答by Pavel S.
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 做的更多的事情,并且具有许多独特的特征:
- distage supports multiple configurations (e.g. you may run your app with different sets of component implementations),
- distage allows you to correctly share dependencies across your tests and easily run same tests for different implementationsof your components,
- distage supports rolesso you may run multiple services within the same process sharing dependencies between them,
- distage does not depend on
scala-reflect(but supports all the necessary features of Scala typesystem, like higher-kinded types).
- disstage 支持多种配置(例如,您可以使用不同的组件实现集运行您的应用程序),
- disstage 允许您在测试之间正确共享依赖项,并轻松地为组件的不同实现运行相同的测试,
- disstage 支持角色,因此您可以在同一进程中运行多个服务,共享它们之间的依赖关系,
- disstage 不依赖
scala-reflect(但支持 Scala 类型系统的所有必要特性,如高级类型)。
You may also watch our talk at Functional Scala 2019where we've discussed and demonstrated some important capabiliteis of distage.
您还可以观看我们在 Functional Scala 2019上的演讲,我们在那里讨论并演示了一些重要的 disstage 能力。
回答by Eric Aldinger
Previous posts covered the techniques. I wanted to add a link to Martin Odersky's May 2014 talk on the Scala language objectives. He identifies languages that "require" a DI container to inject dependencies as poorly implemented. 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. 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.
以前的帖子涵盖了这些技术。我想添加一个指向 Martin Odersky 2014 年 5 月关于 Scala 语言目标的演讲的链接。他认为那些“需要”DI 容器来注入依赖项的语言实现得很差。我个人同意这一点,但这只是一种意见。这似乎表明在您的 Scala 项目中包含 DI 依赖项是不惯用的,但这又是一种意见。实际上,即使使用旨在本地注入依赖项的语言,也可以通过使用容器获得一定程度的一致性。出于您的目的,值得考虑这两种观点。
回答by Marcelo Cantos
I haven't done so myself, but most DI frameworks work at the bytecode level (AFAIK), so it should be possible to use them with any JVM language.
我自己还没有这样做,但大多数 DI 框架都在字节码级别 (AFAIK) 工作,因此应该可以将它们与任何 JVM 语言一起使用。
回答by rintcius
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). This pattern is working very well for me.
除了 Dan Story 的回答之外,我还写了一篇关于 DI 变体的博客,该变体也仅使用语言结构,但在 Jonas 的帖子中未提及:特征值注入(现在链接到 web.archive.org)。这种模式对我来说效果很好。

