如何使用 Guice 重新初始化控制器中注入的组件?

Posted

技术标签:

【中文标题】如何使用 Guice 重新初始化控制器中注入的组件?【英文标题】:How to reinitialize injected component in controller with Guice? 【发布时间】:2016-01-08 14:41:40 【问题描述】:

我有一个控制器:

public class MyController extends Controller 

    private final AuthChecker authChecker;

    @Inject
    public MyController(AuthChecker authChecker) 
        this.authChecker = authChecker;
    

    public Promise<Result> index() throws BusinessException 
        authChecker
            .tokenValue(request().username())
            .execute()
            .go();
        // bla bla bla
    


我对@9​​87654324@ 有疑问,因为它保留了在每个请求之间未重新初始化的内部状态。这个类的初始化是在它的构造函数中完成的,它只执行一次而不是@Singleton

根据Play's documentation:

每次需要组件时都会创建新实例。如果一个 组件被多次使用,然后,默认情况下,多个实例 的组件将被创建。如果您只想要一个实例 一个组件,那么你需要将它标记为一个单例。

我希望每个请求都告诉 Guice 创建一个新实例。 我该如何解决这个问题?

另外,控制器是单例吗?因为它们似乎在整个应用程序生命周期中只被创建一次。

谢谢。

【问题讨论】:

控制器确实是单例的。因此,每个控制器只创建一个“AuthChecker”实例。换句话说,特定控制器的所有请求共享完全相同的authChecker 实例。您可以调整MyController 的scope 或编写AuthChecker 的无状态版本。 IMO 第二种方法是可取的。 谢谢。是的,阅读您的链接后,第二个似乎更可取。但是我们确定Controllers 是线程安全的吗?如果两个请求同时到达会怎样? 要直接回答您的问题,请注入 Provider&lt;AuthChecker&gt; 而不是普通的 AuthChecker @c4k:写好线程安全控制器是你的责任。在这种情况下,两个请求将并行运行并且彼此独立。如果您的控制器不是线程安全的,例如当您在操作中修改实例变量时,应用程序将变得不确定。如果你愿意,我可以在这个周末的某个时候添加一个例子。请告诉我。 @Roman : 是的,我想要一个例子 ;) 【参考方案1】:

您可以使用 Provider,这意味着 guice 会在您每次访问它时创建一个新实例(如果您的模块中没有另外配置):

public class MyController extends Controller 

    private final Provider<AuthChecker> authChecker;

    @Inject
    public MyController(Provider<AuthChecker> authChecker) 
        this.authChecker = authChecker;
    

    public Promise<Result> index() throws BusinessException 
        authChecker.get()
            .tokenValue(request().username())
            .execute()
            .go();
        // bla bla bla
    


【讨论】:

以上是关于如何使用 Guice 重新初始化控制器中注入的组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Guice DI 和 Slick 运行 ScalaTest?

如何从 Guice 的注入器中检索带注释的实例?

TestNG 中使用 Guice 来进行依赖注入

JUnit测试中的Guice注入器[关闭]

使用Dagger2做静态注入, 对比Guice.

Guice - 在构造函数中使用注入字段