简体   繁体   English

如何在没有 Play Framework 的情况下在 Scala 中使用依赖注入?

[英]How to use dependency injection in Scala without Play Framework?

I have experience of developing a web-based application with Scala and Play.我有使用 Scala 和 Play 开发基于 Web 的应用程序的经验。 Play supports Guice out of the box, so it is very easy to do DI with Play. Play 支持开箱即用的 Guice,因此使用 Play 进行 DI 非常容易。

I'm currently working on a Scala project that is not a web application and it does not use Play.我目前正在开发一个 Scala 项目,它不是一个 Web 应用程序,它不使用 Play。 I want to dynamically inject the config object into a few places.我想将配置对象动态注入到几个地方。 How do I do this?我该怎么做呢?

If it is necessary to use some library to do DI, what library is good for this purpose?如果必须使用某个库来做 DI,什么库适合这个目的? Any sample code?任何示例代码? Is it possible to implement this with plain Scala not using any external library?是否可以使用不使用任何外部库的普通 Scala 来实现这一点? When I google "Scala DI without Play", all the results are with Play.当我谷歌“Scala DI without Play”时,所有结果都与Play有关。

Thanks in advance!提前致谢!

Play has nothing to do with dependency injection. Play 与依赖注入无关。 It's handled by Guice - widespread Java DI library.它由Guice处理 - 广泛使用的 Java DI 库。

To grasp the main concepts of Guice I recommend you to read this source .要掌握 Guice 的主要概念,我建议您阅读此来源

I like to use Macwire .我喜欢使用Macwire

Setup设置

Add this line to your build.sbt file:将此行添加到您的build.sbt文件中:

libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.2" % Provided

and then reload.然后重新加载。
Notice that the scope is Provided , so it doesn't add any runtime overhead.请注意,范围是Provided ,因此它不会增加任何运行时开销。 It uses macros to do its job in compile time.它使用宏在编译时完成它的工作。 This means that you get a compile-time dependency injection, and if you are missing a dependency you will find it out as soon as possible - with a compile-time error, rather than getting a runtime exception.这意味着你会得到一个编译时依赖注入,如果你缺少一个依赖,你会尽快找到它 - 带有编译时错误,而不是运行时异常。

Code Example代码示例

  • Let's define two services, X and Y, with some dependencies, A, B, and C, so we can use them later:让我们定义两个服务 X 和 Y,以及一些依赖项 A、B 和 C,以便我们稍后使用它们:
case class A()
case class B()
case class C()
case class X(a: A, b: B)
case class Y(c: C)
  • Now let's wire our dependencies at the end of the world (near the main function):现在让我们在世界尽头(在主函数附近)连接我们的依赖项:
import com.softwaremill.macwire._

lazy val a = wire[A]
lazy val b = wire[B]
lazy val c = wire[C]
lazy val x = wire[X]
lazy val y = wire[Y]
  • The compiler will translate the code above to the following code:编译器会将上面的代码翻译成下面的代码:
lazy val a = new A()
lazy val b = new B()
lazy val c = new C()
lazy val x = new X(a, b)
lazy val y = new Y(c)

This is basically the implementation with plain Scala code, as you asked in your post.正如您在帖子中所问的那样,这基本上是使用纯 Scala 代码的实现。

Changing Dependencies改变依赖

A nice thing here, is that when one of the services changes by adding/removing a dependency, your wiring code will remain the same.这里的一件好事是,当其中一个服务通过添加/删除依赖项而发生变化时,您的接线代码将保持不变。
For example, let's change service Y to also require B as a dependency.例如,让我们将服务 Y 更改为也要求 B 作为依赖项。

  • Our services and dependencies will look like this:我们的服务和依赖项将如下所示:
case class A()
case class B()
case class C()
case class X(a: A, b: B)
case class Y(b: B, c: C)
  • The wiring code will remain the same.接线代码将保持不变。

  • The compiler will translate the wiring code to:编译器会将接线代码转换为:

lazy val a = new A()
lazy val b = new B()
lazy val c = new C()
lazy val x = new X(a, b)
lazy val y = new Y(b, c)

I'm not that sure, but I think you can still use the我不太确定,但我认为你仍然可以使用

"com.google.inject" % "guice" % "4.2.2"

and implement something like this.并实施这样的事情。

class Module extends com.google.inject.AbstractModule {
  protected def configure() = {
    // Example Usage:
    bind(classOf[ClassNameToInjected]).asEagerSingleton()
  }
}

Hope it will helps.希望它会有所帮助。

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

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