Play Framework 2.4 - 依赖注入替换 GlobalSettings.onStart()

Posted

技术标签:

【中文标题】Play Framework 2.4 - 依赖注入替换 GlobalSettings.onStart()【英文标题】:Play Framework 2.4 - Dependency injection to replace GlobalSettings.onStart() 【发布时间】:2015-09-14 00:27:04 【问题描述】:

我对依赖注入感到困惑。我想要实现的是替换 GlobalSettings.onStart() 调用,我在 2.3 中初始化了一些静态单例对象,对这些对象进行了适当的依赖注入。

我想要做的是:

Controller -> Model(将一个对象注入到这个模型中)

到目前为止,我所拥有的只是半途而废;在控制器中:

private static SomeObject myStaticSingletonObject = new SomeObject();

public Promise<Result> getSomeData() 
    return handleRequest(() -> new SomeDataAjaxRequest(myStaticSingletonObject));


public Promise<Result> handleRequest(Function0<AbstractAjaxRequest<?>> supplier) 
    Promise<AbstractAjaxRequest<?>> promise = Promise.promise(supplier);
    return promise.map(arg -> ok(arg.getResponse()));

handleRequest() 是我使用的自定义方法,并没有真正相关,但为了完整性我将其包括在内:

在模型中,我只是将 SomeObject 作为参数:

private final SomeObject someObject;

public SomeDataAjaxRequest(SomeObject someObject) 
    super(null);
    this.someObject = someObject;

在我的 build.sbt 我有:

routesGenerator := InjectedRoutesGenerator

所以基本上我的问题是我应该如何将 SomeObject 注入我的模型以及我应该如何创建我的 SomeObject 对象,我认为我不应该使用new SomeObject()

理想情况下,我想对这些对象使用字段注入,因为我不想弄乱实际上可能具有模型相关参数的构造函数,而不仅仅是这些包含事物定义的实用程序类(SomeObject 基本上只是加载一些来自数据库的信息,目前在应用程序的整个生命周期中都是静态的,但可能会发生变化。

另外值得注意的是,我打算使用 Guice 来管理 DI。

我知道我应该创建一个 Guice DI 工厂,并且已经查看了相关文档,但我仍然不确定如何将它集成到我的 play 应用程序中。

【问题讨论】:

【参考方案1】:

您无需为此显式创建 Guice DI 工厂。

相反,创建一个模块并使用它来配置任何绑定 - 对您来说很重要 - 替换 onStart()

import play.api.inject.Module;

public class SomeModule extends Module 
    @Override
    public Seq<Binding<?>> bindings(final Environment environment,
                                    final Configuration configuration)
    
        return seq(bind(SomeObject.class).toSelf().eagerly());
    

确保使用 javax.inject.Singleton 注释 SomeObject 以确保其状态。模块中eagerly的意义在于保证对象尽早初始化。

SomeObject 将可用于 DI,已被调用一次;你可以使用构造函数来初始化你需要做的任何事情。

要将此模块公开给您的应用程序,请将其添加到application.conf

play 
  modules 
    enabled += "com.example.SomeModule"
  

在你的控制器中,像往常一样注入实例:

public class SomeController extends Controller 
    private final SomeObject someObject;

    @Inject
    public SomeController(final SomeObject someObject) 
        this.someObject = someObject;
    

    public Promise<Result> getSomeData() 
        return handleRequest(() -> new SomeDataAjaxRequest(someObject));
    

    public Promise<Result> handleRequest(Function0<AbstractAjaxRequest<?>> supplier) 
        return Promise.promise(supplier)
                      .map(arg -> ok(arg.getResponse()));
    

【讨论】:

当我在 Play 2.4.2 中尝试此答案顶部的示例代码时,我收到许多编译器错误,例如“...模块必须声明为抽象或实现 configure()”。上面的代码是怎么编译的?自从发表这篇文章以来,Play 发生了很大变化吗?知道在哪里可以找到早期自绑定的工作示例代码吗? 我刚刚注意到导入和超类是错误的 - 我已经更正了示例。 感谢您如此迅速地回复。我见过一些早期的绑定示例。我认为它们适用于 Play 2.4.x。一些实现模块。其他人扩展 AbstractModule。这两种方法之间有什么重要区别吗? Module 是 Play-internal,因此如果您正在编写一个用于一般消费的模块,它不会强制依赖像 Guice 这样的特定框架。如果您正在编写一些供内部使用的东西,您可以使用特定于框架的类,例如 Guice 的 AbstractModule。请参阅this 了解更多信息。 谢谢。现在我的模块编译了!下一步是找出获取环境配置的新 Play 方式。看起来public static final String myVar = Play.application().config().getString(...) 可能会在我的早期绑定组件中导致启动错误。

以上是关于Play Framework 2.4 - 依赖注入替换 GlobalSettings.onStart()的主要内容,如果未能解决你的问题,请参考以下文章

Play Framework 2.4 - 注入的字段始终为空

Play Framework 2.4 在 Scala 模板中使用注入变量

Play framework + Scala:使用动作组合注入依赖

在 Akka actor 中玩 2.4 依赖注入

Play 2.4 WebSocket在使用编译时依赖注入时抛出InstantiationException

Play Framework 2.4 发送邮件