它基本上是这样的:
class MyComponent @Inject() (mailerClient: MailerClient) { ... }
足够简单,它编译不符合要求
然后我尝试“调用”它然而似乎没有办法满足编译器或获得mailerClient的工作实例.
object AnObject { val mailer = new MyComponent def sendEmail = mailer.doStuff } [info] Compiling 1 Scala source to ... [error] /SomeOne/SomePath/SomeFile.scala:30: not enough arguments for constructor MyComponent: (mailerClient: play.api.libs.mailer.MailerClient) MyComponent. [error] Unspecified value parameter mailerClient. [error] val mailer = new MyComponent [error] ^ [error] one error found [error] (compile:compileIncremental) Compilation Failed
我可能因为这个而接近了:
How does @Inject in Scala work
这表明通过从构造函数中删除@Inject并将其放在字段上,以下语法可能会起作用.
@Inject var mailerClient: MailerClient = null
然而,当我们尝试运行任何需要该引用的东西时,我们仍然会得到null.
我正在阅读@Inject上可以找到的所有内容
([警告] [咆哮]我不是这样的编译器魔法粉丝这个确切的原因 – 伏都教魔法很棒,直到它停止工作然后似乎没有人知道如何解决它.[/ rant] [/警告] )
但我真正想知道的是如何正确,安全和有效地使用它.
解决方法
首先,实例化实例的方式并没有给DI框架注入依赖关系的机会.由于new是一个语言关键字,因此DI无法干预,并且无法注入您所需的类依赖关系.如何完成是通过构造函数或字段注入.我将主要关注构造函数注入,因为它是scala世界中的“标准”.
如果使用@Injected批注指定构造函数参数,则基本上是告诉DI框架从容器中解析此依赖关系. DI框架在其容器内查找该对象的条目.如果它不存在,它将创建它(并在进程中解析其依赖关系),如果它使用@Singleton注释,也保存此实例以供将来使用.大多数DI框架要求您在大多数情况下指定起始类,但因为您正在使用Play!这个框架没有必要.如果要在控制器中使用特定模块,可以执行以下操作:
import javax.inject.Inject import play.api.mvc.Controller class Test @Inject() (val dependency: FooClass) extends Controller { ... }
在这种情况下,FooClass是要注入控制器的依赖项的类名.假设FooClass将Play的应用程序作为依赖项注入,因为Play提供了几个预绑定的预设,如Application,还有ActorSystem.
这是可能的,因为玩! Framework使用DependencyInjectedRoutes.如果您要在Controller之外创建一个Actor,则需要在模块类中指定它,但在此link和link中对此进行了解释.
还有一个概念是在控制器中使用Traits,然后将特性与实现类连接起来,但我认为现在有点太复杂了.
如果你想要这种编写应用程序的方法有一些好处和成功的故事,这里有一个很好的资源:https://softwareengineering.stackexchange.com/a/19204/164366
如果你想要阅读这个概念:
> https://www.playframework.com/documentation/2.4.x/ScalaAkka
> https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection
> https://www.playframework.com/documentation/2.4.x/ScalaCompileTimeDependencyInjection
我希望这能解决问题!如果您有疑问,请询问!