我使用Akka和Guice依赖注入在我的Play Framework应用中使用IndirectActorProducer
的模式。
像这样:
import akka.actor.Actor;
import akka.actor.IndirectActorProducer;
import play.api.inject.Injector;
public class GuiceActorProducer implements IndirectActorProducer {
private Injector injector;
private Class<Actor> cls;
public GuiceActorProducer(Injector injector, Class<Actor> cls) {
this.injector = injector;
this.cls = cls;
}
@Override
public Actor produce() {
return injector.instanceOf(cls);
}
@Override
public Class<? extends Actor> actorClass() {
return Actor.class;
}
}
这非常适合创建100%注入的actor,如下所示:
ActorRef imageGenerator = actorService.getActorSystem().actorOf(
Props.create(GuiceActorProducer.class, injector, ImageGenerator.class),
String.format("ImageGenerator-%d", brandId));
不幸的是,我有50%注入的演员和50%&#34;辅助&#34;。他们有这样的工厂:
public interface Factory {
Synchronizer create(@Assisted("taskLogId") Long taskLogId, @Assisted("clientGroup") String clientGroup, @Assisted boolean messagesOnly, @Assisted("notes") String notes);
}
他们在模块中绑定了这样的内容:
bindActorFactory(Synchronizer.class, SynchronizerProtocol.Factory.class);
当我想创建一个Synchronizer actor时,我尝试这样但它不起作用。没有错误但它根本没有输入构造函数。这是正常的,我没有提供所需的参数......
ActorRef myActor = actorService.getActorSystem().actorOf(
Props.create(GuiceActorProducer.class, injector, Synchronizer.class), synchronizerName);
我不知道在哪里使用这种语法提供我的4个参数。我非常确定我需要将它们送到注射器,但是我无法找到关于这个的任何文档,也没有找到api中指向这个方向的任何函数。
这是同步器的构造函数,只是为了清楚。它需要注入,因为它有很多工厂来创建其他objets。此外,Synchronizer actor需要在普通对象(而不是actor)中创建,并且需要命名为
@Inject
private Synchronizer(SyncStateErrorUserNotification.Factory syncStateErrorUserNotificationFactory,
NewBrandStationLinkUserNotification.Factory newBrandStationLinkUserNotificationFactory,
MediaUpdaterProtocol.Factory mediaUpdatersFactory,
StationSyncFileGeneratorProtocol.Factory stationSyncFileGeneratorsFactory,
StationSynchronizerProtocol.Factory stationSynchronizerFactory,
BrandSyncFileGeneratorProtocol.Factory brandSyncFileGeneratorsFactory,
PlaylistUpdaterProtocol.Factory playlistUpdatersFactory,
Injector injector,
StationScheduleStyleService stationScheduleStyleService,
LogCreationService logCreationService,
CustomSqlManagerService customSqlManagerService,
SongSynchronizerProtocol.Factory songSynchronizerFactory,
ClientGroupSynchronizerProtocol.Factory clientGroupSynchronizersFactory) {
super(logCreationService);
this.syncStateErrorUserNotificationFactory = syncStateErrorUserNotificationFactory;
this.newBrandStationLinkUserNotificationFactory = newBrandStationLinkUserNotificationFactory;
this.mediaUpdatersFactory = mediaUpdatersFactory;
this.playlistUpdatersFactory = playlistUpdatersFactory;
this.injector = injector;
this.stationScheduleStyleService = stationScheduleStyleService;
this.logCreationService = logCreationService;
this.customSqlManagerService = customSqlManagerService;
this.stationSyncFileGeneratorsFactory = stationSyncFileGeneratorsFactory;
this.brandSyncFileGeneratorsFactory = brandSyncFileGeneratorsFactory;
this.stationSynchronizerFactory = stationSynchronizerFactory;
this.songSynchronizerFactory = songSynchronizerFactory;
this.clientGroupSynchronizersFactory = clientGroupSynchronizersFactory;
}
帮助!感谢
答案 0 :(得分:1)
AssistedInject 。 Guice不能自己创建这样的实例。
工厂来帮助Guice创建实例:这个工厂是一个接口,它有一个方法(或几个方法)接收所有未注入的参数并返回一个适当的实例。
工厂界面安装在模块中,而不是绑定类。注入工厂而不是类实例;它用于创建类实例。您可以看到here更详细的说明和示例。
辅助注射的Akka方式是 IndirectActorProducer 。 Play在面纱下做了一些事情并建议了辅助注射的另一种模式,就像在documentation中解释的那样。
我个人发现在Play中使用辅助注入需要太多的样板代码,它应该作为最后的选择。我将展示两个选项:如何使用非注入参数注入actor(也就是通过辅助注入)以及如何使用Props创建它。
Synchronizer具有Factory接口,用于注入actor实例而不是Props:
SELECT *
FROM tbl
WHERE site Like "*" & [Forms]![NavigationForm]![NavigationSubform].[Form]![comboBox] & "*";
Play要求父级演员,这将提供辅助注入儿童演员。比方说,它是SynchronizerParent。父级在收到CreateSynchronizer消息时注入子节点,该消息封装了创建Synchronizer所需的所有参数。它将注入的子节点的ActorRef发送给调用者:
public class Synchronizer extends UntypedActor {
private final Long taskLogId;
private final String clientGroup;
private final boolean messagesOnly;
private final String notes;
@Inject
public Synchronizer(@Assisted Long taskLogId, @Assisted("clientGroup") String clientGroup, @Assisted boolean messagesOnly, @Assisted("notes") String notes) {
this.taskLogId= taskLogId;
this.clientGroup= clientGroup;
this.messagesOnly= messagesOnly;
this.notes= notes;
}
@Override
public void onReceive(Object message) throws Exception {
...
}
// The factory
public interface Factory {
public Actor create(Long taskLogId, String clientGroup, boolean messagesOnly, String notes);
}
}
模块中的绑定(应该实现AkkaGuiceSupport):
public class SynchronizerParent extends UntypedActor implements InjectedActorSupport {
//Protocol
public static class CreateSynchronizer {
private final Long taskLogId;
private final String clientGroup;
private final boolean messagesOnly;
private final String notes;
private final String brandId;
public CreateSynchronizer(
Long taskLogId, String clientGroup,
boolean messagesOnly, String notes, String brandId) {
this.taskLogId = taskLogId;
this.clientGroup = clientGroup;
this.messagesOnly = messagesOnly;
this.notes = notes;
this.brandId= brandId;
}
}
private Synchronizer.Factory childFactory;
@Inject
public SynchronizerParent(Synchronizer.Factory childFactory) {
this.childFactory = childFactory;
}
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof CreateSynchronizer) {
injectSynchronizer((CreateSynchronizer)message);
}
else {
unhandled(message);
}
}
private void injectSynchronizer(CreateSynchronizer injectMsg) {
ActorRef child = injectedChild(() -> childFactory.create(
injectMsg.taskLogId,
injectMsg.clientGroup,
injectMsg.messagesOnly,
injectMsg.notes)
, "child-" +injectMsg.brandId);
sender().tell(child, self());
}
}
Actors服务使用 ask pattern :它将CreateSynchronizer消息发送给父actor,并期望将ActorRef接收回注入的子节点:
public class ActorsModule extends AbstractModule implements AkkaGuiceSupport {
@Override
protected void configure() {
bindActor(SynchronizerParent.class, "parentActor");
bindActorFactory(Synchronizer.class, Synchronizer.Factory.class);
}
}
Syncronizer现在包含一个静态工厂方法props而不是Factory接口:
public class ActorsServiceImpl extends ActorsService {
private ActorRef parentActor;
@Inject
public ActorsServiceImpl(@Named("parentActor") ActorRef parentActor) {
this.parentActor = parentActor;
}
public CompletionStage<ActorRef> createSyncronizer(Long taskLogId, String clientGroup, boolean messagesOnly, String notes, String brandId) {
// Use guice assisted injection to instantiate and configure the child actor.
long timeoutMillis = 100L;
return FutureConverters.toJava(
ask(parentActor,
new SynchronizerParent.CreateSynchronizer(taskLogId, clientGroup, messagesOnly, notes),
brandId),
timeoutMillis))
.thenApply(response -> (ActorRef) response);
}
}
演员服务实施:
public class Synchronizer extends UntypedActor {
private final Long taskLogId;
private final String clientGroup;
private final boolean messagesOnly;
private final String notes;
// Factory method
public static Props props(Long taskLogId, String clientGroup, boolean messagesOnly, String notes) {
return Props.create(Synchronizer.class, taskLogId, clientGroup, messagesOnly, notes);
}
public Synchronizer(Long taskLogId, String clientGroup, boolean messagesOnly, String notes) {
this.taskLogId= taskLogId;
this.clientGroup= clientGroup;
this.messagesOnly= messagesOnly;
this.notes= notes;
}
@Override
public void onReceive(Object message) throws Exception {
...
}
}
我绝对更喜欢使用第二种选择。