Scala (Play 2.4.x) 如何使用@inject() 注释调用类 [英] Scala (Play 2.4.x) How to call a class with @inject() annotation

查看:37
本文介绍了Scala (Play 2.4.x) 如何使用@inject() 注释调用类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看 play-mailer 的鳞状代码示例:https://github.com/playframework/play-mailer

I'm looking at the scaly code example from play-mailer: https://github.com/playframework/play-mailer

基本上是这样的:

class MyComponent @Inject() (mailerClient: MailerClient) {
   ...
}

足够简单,编译时不合规

simple enough and it compiles without compliant

然后我尝试调用"它,但似乎没有办法满足编译器或获取 mailerClient 的工作实例.

Then I try to "call" it however and there doesn't appear to be a way to satisfy the compiler OR get a working instance of 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

我想我可能已经接近了:

I though I might have gotten close thanks to this:

Scala 中的@Inject 是如何工作的

这表明通过从构造函数中删除 @Inject 并将其放置在字段上,以下语法可能会起作用.

Which indicated that the following syntax might work by removing the @Inject from the constructor and placing it on a field.

@Inject var mailerClient: MailerClient = null

然而,当我们尝试运行任何需要该引用的东西时,我们仍然会得到 null.

However the moment we try to run anything that needs that reference we still get null.

我正在阅读我能在@Inject 上找到的所有内容

I'm reading everything I can find on @Inject

( [警告] [咆哮] 由于这个确切的原因,我不是这样的编译器魔法的粉丝——伏都教魔法很棒,直到它停止工作然后似乎没有人知道如何修复它.[/rant] [/warning] )

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

but what I really want to know is how to use it properly, safely and effectively.

推荐答案

由于您在原始 GitHub 存储库上关闭了您的问题,我不知道这个答案是否仍然必要,但由于您不完全了解使用DI 框架,我发现学习这项技能非常重要,我将尝试在这里解释它并列出一些好处.

Since you closed your issue on the original GitHub repo, I don't know if this answer is still necessary but since you don't fully understand the use of a DI framework and I find it incredibly important to learn this skill, I'll try to explain it here and list some benefits.

首先,您实例化实例的方式不会给 DI 框架注入依赖项的机会.由于 new 是语言关键字,因此 DI 无法干扰并且无法注入您的类所需的依赖项.它是如何通过构造函数或字段注入完成的.我将主要关注构造函数注入,因为这是 Scala 世界中的标准".

First off, the way you are instantiating your instance doesn't give the DI framework a chance to inject your dependencies. Since new is a language keyword, DI can't interfere and the dependencies you need for your class can't be injected. How it is done is through constructor or field injection. I'll mainly focus on constructor injection because that is "standard" in the scala world.

如果您使用 @Injected 批注指定构造函数参数,您基本上是在告诉 DI 框架从容器解析此依赖项.DI 框架会在其容器内查找该对象的条目.如果它不存在,它将创建它(并在过程中解决它的依赖项),如果它用 @Singleton 注释,也保存这个实例以备将来使用.大多数 DI 框架要求您在大多数情况下指定一个起始类,但因为您使用的是 Play!框架这不是必需的.当您想在控制器中使用特定模块时,您可以这样做:

If you specify a constructor argument with the @Injected annotation, you are basically telling the DI framework to resolve this dependency from the container. The DI framework goes and looks for an entry of that object inside its container. If it doesn't exists, it will create it (and resolve its dependencies in the process) and if it's annotated with @Singleton also save this instance for future use. Most DI frameworks require you to specify a starting class in most cases but because you are using Play! Framework this is not necessary. When you want to use a particular module inside your controller you can do this:

import javax.inject.Inject

import play.api.mvc.Controller

class Test @Inject() (val dependency: FooClass) extends Controller {
  ...
}

在这种情况下,FooClass 是您要注入控制器的依赖项的类名.假设 FooClass 有 Play 的 Application 作为依赖项,这将被注入,因为 Play 提供了几个预绑定的预设,如 Application>ActorSystem.

In this case FooClass is the class name of the dependency you want to inject into your controller. Let's say FooClass has Play's Application as a dependency this will be injected, because Play provides a couple pre-bonded presets like Application but also ActorSystem.

这是可能的,因为 Play!框架使用 DependencyInjectedRoutes.如果您要在控制器之外创建一个 Actor,您需要在模块类中指定它,但这在此 链接 和这个链接.

This is possible because Play! Framework uses DependencyInjectedRoutes. If you were to create an Actor outside of an Controller you would need to specify that inside a module class but that is explained in this link and this link.

还有一个在你的控制器中使用 Traits 的概念,然后将特征与实现类连接在一起,但我认为现在这有点太复杂了.

There is also a concept of using Traits inside your controller and then later on wiring together the traits with the implementation classes but I think that is a bit too complicated for now.

如果您想了解这种编写应用程序的方法的好处和成功案例,这里有一个很好的资源:https://softwareengineering.stackexchange.com/a/19204/164366

If you want some benefits and succes stories to this method of writing applications, here is a good resource: https://softwareengineering.stackexchange.com/a/19204/164366

如果您想了解有关此概念的内容:

If you want something to read on this concept:

我希望这能解决问题!如果您有问题,请尽管提问!

I hope this clears things up! If you have question, please do ask!

这篇关于Scala (Play 2.4.x) 如何使用@inject() 注释调用类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆