2015-07-10 40 views
7

我期待在从播放邮件的鳞屑代码示例:https://github.com/playframework/play-mailer斯卡拉(播放的2.4.x)如何调用与@Inject()注释类

它去基本上是这样的:

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 

但是,当我们尝试运行任何需要该引用的东西时,我们仍然得到空值。

我读的一切,我可以找到关于@Inject

([警示] [咆哮]我不是这个确切原因的编译器魔术这样的风扇 - 巫术是美好的,直到它[/ rant] [/ warning])

但我真正想知道的是如何正确,安全和有效地使用它。

+0

仅供参考 - 这可能有助于那些只是为了让电子邮件工作... https://github.com/playframework/play-mailer/blob/master/src/test/scala/play/api/libs/mailer /MailerPluginSpec.scala – Techmag

回答

0

这不是一个scala问题,而是一个DI问题。您应该阅读一些guice文档。

在Play 2.4.x中,您需要使用依赖注入(https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection) 来实现您的目标。

你AnObject应该是:

@Singleton class AnObject @Inject()(mailer:MyComponent){ 
def sendEmail = mailer.doStuff 
} 
+1

嗯:Guice的目标是使开发和调试更容易,更快,而不是更难和更慢。就此而言,吉斯避开了惊喜和魔法。 ??? – Techmag

+0

工厂和单身人士现在看起来真的很棒。 – Techmag

+1

仍然没有解决原来的问题 - 我们只是把它放到另一个类中 - 我现在要如何调用(使用)这个AnObject,编译器需要一个AnObject的邮件参数。告诉我如何从一个物体中使用它 - 我知道这是与Guice试图做的对比 - 但至少我可以从那里拿走它。 – Techmag

10

既然你关闭你的问题对原GitHub库,我不知道这个答案仍然是必要的,但因为你没有完全了解使用的DI框架,我发现学习这个技能非常重要,我会试着在这里解释它并列出一些好处。

首先,你实例化你的实例的方式不会给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的Application作为依赖项注入,因为Play提供了一对预先绑定的预设,例如Application,还有ActorSystem

这是可能的,因为玩!框架使用DependencyInjectedRoutes。如果要在控制器之外创建一个Actor,则需要在模块类中指定该角色,但在此​​和link中解释了这一点。

在你的控制器里面还有一个使用Traits的概念,然后再把这些特性和实现类连接起来,但我认为这有点太复杂了。

如果你想要一些好处和更迭的故事的编写应用这种方法,这里是一个很好的资源:https://softwareengineering.stackexchange.com/a/19204/164366

如果你想要的东西,对这个概念阅读:

我希望这可以解决问题!如果你有问题,请不要问!

+0

我完全理解DI-THAT的目的和要求不是问题 - 我已阅读了大部分Guice文档 - 包括与@Inject进程(及其所有相关选项)有关的所有内容,然而我仍然无法访问“@ Injected”对象。我认为Play有一些魔术可以让控制器拥有可注入的构造函数。文档中的某些内容暗示零参数构造函数是变幻莫测的,而@ @ Injected是由它调用的(或者反之亦然)。 – Techmag

+0

也许'@ Injected'对象只能在“对象内部”使用 - 但即使这是真的,那么为什么每次尝试在运行时使用字段注入都会导致空指针呢?我在Global.scala启动(并绑定)了Guice,并且已经追踪它以确保它实际上按照预期加载。所以这个问题(和我的原始问题)仍然存在。我想知道的仅仅是缺少一部分来访问'@ Injected' Objects ... – Techmag

+1

这个dosn't回答这个问题,我有同样的问题。如果在我想要使用该类时必须传入对象,那么在类构造函数中使用DI的意义是什么 – Ir1sh

0

我遇到了同样的问题。我想创建一个具有邮件功能的类或对象,然后当我想从任何控制器发送电子邮件时,我可以调用它。

我想你所问的等同于如何使用mailerclient外部播放框架。据我所知,你不能。即使你在app/controllers文件夹中创建了一个类,它只是一个普通的scala类,与play框架中的魔术无关。 @Inject仅适用于控制器或模块。因为如果你创建一个独立的类,你必须在实例化时自己注入一些东西。除非您正在构建模块或扩展控制器。你注意到AppController曾经是对象,现在它是一个类?当你使用它时,你不需要实例化。我相信框架通过配置(注入)来实例化它。所以如果你想达到最初的设计目标,你可以编写一个模块,发布它,然后在所有的控制器中使用它;或者使用scala中的一些其他电子邮件库来包装电子邮件发送功能。

+0

因为我很痛苦地发现真正的答案是Injected类只能通过一个Injected类来实例化(这就是它们一直表现出来的海龟的含义)。这不是真的,你需要在控制器中这样做 - 它只是由于上述规则而出现。最早可以获得“板载”的东西以前是GlobalSettings,它现在已经迁移到了'play.modules.enabled'配置项。你可以创建自己的Injectable类,但它们也必须通过另一个Injected类(该死的一堆乌龟)拾取。一位威士忌探戈Foxtrot的情况恕我直言:) – Techmag

+0

这就是我的意思是通过创建一个模块。即使你可以用@inject创建一个类,如果它不是一个控制器或一个模块,在你使用它的时候你仍然必须实例化,在这种情况下这是无奈的。 – yang

0

(我没有足够的信誉发表评论,所以张贴作为一个答案)

发表@aparo答案应该被标记为corect /认可的答案,因为它确实解决问题。你说这不能解决原来的问题,因为它会将依赖关系转移到另一个类中,但这只是部分正确的,因为其他类只需向您提供MyComponent而不是MailerClient。虽然依赖注入需要一直使用到最终控制器(在Play的情况下),但通常不需要注入更多的单个对象。

这个证明可以看出in a question I posted,因为我在当时与你有相同的心态。在我的例子中,我的控制器只需要一个UserSearch依赖关系,依赖关系由guice处理,所以我不需要再次声明它。

+0

我终于与DI达成了和平(或者至少是Guice in Play),而魔幻时刻正在接受为了获得一个Injected组件,首先你必须注入一个注入组件。问题是(我怀疑)超过一些人将会退出注射循环,并因此提出一个像我一样的问题,永远无法令人满意地回答。 (所有试验都会导致NULL激发文档*似乎*的说法。)我计划回来并记录下*作为帮助其他人阻止我循环的最长时间的答案...... – Techmag