【问题标题】:Access to Play 2 ActorSystem reference within a Module访问模块中的 Play 2 ActorSystem 引用
【发布时间】:2017-11-29 15:22:28
【问题描述】:

根据documentation Play 2.6:

删除了已弃用的静态方法 play.libs.Akka.system 和 play.api.libs.concurrent.Akka.system。使用依赖注入获取 ActorSystem 的实例并访问 Actor 系统。

该文档提供了一个使用 POJO 注释的示例,但是在模块中使用时语法似乎不起作用...

我们的类定义如下:

public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {...}

1) 尝试对类成员使用 @Inject 会产生 NULL 引用:

    @Inject
    protected ActorSystem system;

2) 尝试在模块的构造函数上使用 @Inject 会抛出 play.api.PlayException: No valid constructors

    public SomeMagicalModule (@Inject AkkaSystem system) {...}

还有其他途径可以获取 AkkaSystem,还是我们缺少一些简单的东西?

TIA。

【问题讨论】:

    标签: java dependency-injection playframework akka guice


    【解决方案1】:

    你可以使用@Provides

    当您需要代码来创建对象时,请使用@Provides 方法。该方法必须在模块中定义,并且必须具有@Provides 注释。该方法的返回类型是绑定类型。 只要注入器需要该类型的实例,它就会调用该方法。 如果@Provides 方法有一个像@PayPal 或@Named("Checkout") 这样的绑定注解,Guice 会绑定注解的类型。 依赖关系可以作为参数传递给方法。在调用方法之前,注入器将执行每个这些的绑定。

    @Provides
    CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
      PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
      processor.setApiKey(apiKey);
      return processor;
    }
    

    但是,你应该考虑到

    只要注入器需要该类型的实例,它就会调用该方法

    因此,如果您有两个依赖于 Provided 组件的组件,在本例中为 CreditCardProcessor,您最终将得到该组件的 2 个实例,因为 Guice 注入器调用了该方法每次需要注入这种类型的实例。

    Scopes 提供解决方案,您必须添加 @Singleton 注释。

    @Provides
    @Singleton
    CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
      PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
      processor.setApiKey(apiKey);
      return processor;
    }
    

    你的情况是

    public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {
    
      @Provides
      @Singleton
      @Named("some-actor")
      ActorRef createActor(system: ActorSystem){
        system.actorOf(...)
      }
    }
    

    感谢 codejanovic,请参阅 his answer

    无论如何,如果你想引用 ActorSystem 来创建 Actor,你应该使用AkkaGuiceSupport(我看到你已经将它添加到你的模块中但你似乎没有使用它)。

    【讨论】:

    • 非常详细 - 谢谢。我已将此标记为帖子的“答案”,因为它触及了问题的核心:如何在模块中访问 Play 的 ActorSystem。
    【解决方案2】:

    模块实际上不能有@Inject 注释。您使用模块来配置注入的工作方式,但您不能将东西注入其中。原因是 Play/Guice 首先创建和配置所有模块,然后然后进行注入。配置完成后才能进行注入。

    关于模块的 Guice 文档:https://github.com/google/guice/wiki/Bindings#creating-bindings

    您可以在 Guice 创建的其中一个对象中获得ActorSystem,例如控制器:

    public class MyController {
      @Inject // <--- goes before constructor not on parameter
      public MyController(ActorSystem actorSystem) { ... }
      ...
    }
    

    关于@Inject的Guice文档:https://github.com/google/guice/wiki/Injections#injections

    【讨论】:

    • 感谢您的洞察力,Rich。我们终于厌倦了尝试,只是将代码放入绑定在该模块中的生成的 Actor 中。不是我们真正想要的,但它暂时会做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多