访问模块中的 Play 2 ActorSystem 参考
Access to Play 2 ActorSystem reference within a Module
根据 documentation 对于 Play 2.6:
The deprecated static methods play.libs.Akka.system and play.api.libs.concurrent.Akka.system were removed. Use dependency injection to get an instance of ActorSystem and access to the actor system.
该文档提供了一个使用 POJO 注释的示例,但是在模块中使用时语法似乎不起作用...
我们的 Class def 看起来像这样:
public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {...}
1) 尝试在 class 成员上使用 @Inject 会产生 NULL 引用:
@Inject
protected ActorSystem system;
2) 尝试在模块的构造函数上使用 @Inject 抛出 play.api.PlayException: 没有有效的构造函数 :
public SomeMagicalModule (@Inject AkkaSystem system) {...}
是否有其他获取 AkkaSystem 的途径,或者我们是否遗漏了一些简单的东西?
TIA。
模块实际上不能有 @Inject
注释。您使用模块来配置注入的工作方式,但您不能将东西注入其中。原因是 Play/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
的指南文档:https://github.com/google/guice/wiki/Injections#injections
可以使用@Provides
When you need code to create an object, use an @Provides method. The method must be defined within a module, and it must have an @Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method.
If the @Provides method has a binding annotation like @PayPal or @Named("Checkout"), Guice binds the annotated type. Dependencies can be passed in as parameters to the method. The injector will exercise the bindings for each of these before invoking the method.
@Provides
CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
return processor;
}
但是,您应该考虑到
Whenever the injector needs an instance of that type, it will invoke the method
因此,如果您有两个组件依赖于 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 来创建 Actors,您应该使用 AkkaGuiceSupport(我看到您已经将它添加到您的模块中,但您似乎没有使用它)。
根据 documentation 对于 Play 2.6:
The deprecated static methods play.libs.Akka.system and play.api.libs.concurrent.Akka.system were removed. Use dependency injection to get an instance of ActorSystem and access to the actor system.
该文档提供了一个使用 POJO 注释的示例,但是在模块中使用时语法似乎不起作用...
我们的 Class def 看起来像这样:
public class SomeMagicalModule extends AbstractModule implements AkkaGuiceSupport {...}
1) 尝试在 class 成员上使用 @Inject 会产生 NULL 引用:
@Inject
protected ActorSystem system;
2) 尝试在模块的构造函数上使用 @Inject 抛出 play.api.PlayException: 没有有效的构造函数 :
public SomeMagicalModule (@Inject AkkaSystem system) {...}
是否有其他获取 AkkaSystem 的途径,或者我们是否遗漏了一些简单的东西?
TIA。
模块实际上不能有 @Inject
注释。您使用模块来配置注入的工作方式,但您不能将东西注入其中。原因是 Play/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
的指南文档:https://github.com/google/guice/wiki/Injections#injections
可以使用@Provides
When you need code to create an object, use an @Provides method. The method must be defined within a module, and it must have an @Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method. If the @Provides method has a binding annotation like @PayPal or @Named("Checkout"), Guice binds the annotated type. Dependencies can be passed in as parameters to the method. The injector will exercise the bindings for each of these before invoking the method.
@Provides
CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
return processor;
}
但是,您应该考虑到
Whenever the injector needs an instance of that type, it will invoke the method
因此,如果您有两个组件依赖于 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 来创建 Actors,您应该使用 AkkaGuiceSupport(我看到您已经将它添加到您的模块中,但您似乎没有使用它)。