现代Akka DI与Guice

问题描述 投票:10回答:5

这里有Java 8,Guice 4.0和Akka 2.3.9。我试图弄清楚如何使用JSR330样式的@Inject注释来注释我的actor类,然后通过Guice将它们连接起来。

但实际上,我读过的每一篇文章(下面的一些例子)都使用了Scala代码示例,一个犯罪版本的Guice,或者是一个犯罪旧版本的Akka:

因此,给出以下Guice模块:

public interface MyService {
    void doSomething();
}

public class MyServiceImpl implements MyService {
    @Override
    public void doSomething() {
        System.out.println("Something has been done!");
    }
}

public class MyActorSystemModule extends AbstractModule {
    @Override
    public void configure() {
        bind(MyService.class).to(MyServiceImpl.class);
    }
}

鉴于FizzActor注入了MyService

public class FizzActor extends UntypedActor {
    private final MyService myService;

    @Inject
    public FizzActor(MyService myService) {
        super();

        this.myService = myService;
    }

    @Override
    public void onReceive(Object message) {
        // .. Do fizz stuff inside here.
    }
}

然后我问:我如何装配MyActorSystemModule来创建FizzActor的实例并正确地用Java注入它们(而不是Scala!)?

请注意:FizzActor不是我演员系统中唯一的演员!

java akka guice
5个回答
7
投票

使用Creator在guice模块的提供者方法中创建ActorRefs。要区分不同类型的不同ActorRefs,请在提供者方法和注入点上使用注释,就像使用任何guice系统一样。例如,

在你的guice模块中:

@Override
protected void configure() {
    bind(ActorSystem.class).toInstance(ActorSystem.apply());
    bind(FizzService.class).toInstance(new FizzServiceImpl());
}

@Provides @Singleton @Named("fizzActor")
ActorRef serviceActorRef(final ActorSystem system, final FizzService fizzService) {
    return system.actorOf(Props.create(new Creator<Actor>() {
        @Override
        public Actor create() throws Exception {
            return new FizzActor(fizzService);
        }
    }));
}

然后使用actor服务,注入一个特定的ActorRef

class ClientOfFizzActor {
    @Inject
    ClientOfFizzActor(@Named("fizzActor") ActorRef fizzActorRef) {..}
}

如果Props.create(..)子句是actor类中的静态工厂方法,它看起来更干净。


3
投票

除非您尝试将UntypedActor绑定到FizzActor,否则您可以将其注入其他类中:

class SomeOtherClass {

    @Inject 
    public SomeOtherClass(FizzActor fizzActor) {
        //do stuff
    }
}

如果您尝试将其绑定到接口,则需要在模块中专门执行此操作:

public class MyActorSystemModule extends AbstractModule {
    @Override
    public void configure() {
        bind(MyService.class).to(MyServiceImpl.class);
        bind(UntypedActor.class).to(FizzActor.class);
    }
}

编辑:

如何使用@Named来区分UntypedActor,例如:

class SomeOtherClass {

    @Inject 
    public SomeOtherClass(@Named("fizzActor")UntypedActor fizzActor, @Named("fooActor") UntypedActor fooActor) {
        //do stuff
    }
}

然后在您的模块中,您可以执行akka查找:

public class MyActorSystemModule extends AbstractModule {

    ActorSystem system = ActorSystem.create("MySystem");

    @Override
    public void configure() {
        bind(MyService.class).to(MyServiceImpl.class);
    }

    @Provides
    @Named("fizzActor")
    public UntypedActor getFizzActor() {
        return system.actorOf(Props.create(FizzActor.class), "fizzActor");
    }

    @Provides
    @Named("fooActor")
    public UntypedActor getFooActor() {
        return system.actorOf(Props.create(FooActor.class), "fooActor");
    }
}

2
投票

使用akka Creator

public class GuiceCreator<T> implements Creator<T> {
 Class<T> clz;
 Module module;
 /*Constructor*/

 public T create() {
    Injector injector = Guice.createInjector(this.module);
    return injector.getInstance(this.clz);
  }
}

然后使用Props.create和你的闪亮的新guice创建者。

免责声明:我实际上并不了解Akka,提到的信息来自浏览文档和JavaDoc。


0
投票

如果有人发现这个问题,你需要使用IndirectActorProducer,我参考了Spring的例子,并将其改为使用Guice。

/**
 * An actor producer that lets Guice create the Actor instances.
 */
public class GuiceActorProducer implements IndirectActorProducer {
    final String actorBeanName;
    final Injector injector;
    final Class<? extends Actor> actorClass;

    public GuiceActorProducer(Injector injector, String actorBeanName, Class<? extends Actor> actorClass) {
        this.actorBeanName = actorBeanName;
        this.injector = injector;
        this.actorClass = actorClass;
    }

    @Override
    public Actor produce() {
        return injector.getInstance(Key.get(Actor.class, Names.named(actorBeanName)));
    }

    @Override
    public Class<? extends Actor> actorClass() {
        return actorClass;
    }
}

在模块中

public class BookingModule extends AbstractModule {

    @Override
    protected void configure() {               
        // Raw actor class, meant to be used by GuiceActorProducer.
        // Do not use this directly
        bind(Actor.class).annotatedWith(
                Names.named(BookingActor.ACTOR_BEAN_NAME)).to(
                BookingActor.class);
    }

    @Singleton
    @Provides
    @Named(BookingActor.ACTOR_ROUTER_BEAN_NAME)
    ActorRef systemActorRouter(Injector injector, ActorSystem actorSystem) {
      Props props = Props.create(GuiceActorProducer.class, injector, BookingActor.ACTOR_BEAN_NAME, actorClass);
      actorSystem.actorOf(props.withRouter(new RoundRobinPool(DEFAULT_ROUTER_SIZE)), BookingActor.ACTOR_ROUTER_BEAN_NAME);
    }
}

0
投票

所以我最近一直在玩Akka和Guice很多,我觉得那两个人在一起玩的不太好。

我建议你采取与Play相似的方法。

Kutschkem的答案最接近于此。

  1. 使用ActorCreator接口
  2. 确保你有一个无争议的Creator。不要试图在你的@AssisstedInject中做Creator,因为这意味着你需要为你想要创建的每个Actor创建一个新的创建者。我个人认为,通过消息传递更好地在演员中初始化它。
  3. 让ActorCreator使用一个注入器,以便您可以在Creator中轻松创建Actor对象。

这是使用当前Akka 2.5的代码示例。这是我们为Akka 2.5部署选择的首选设置。为简洁起见,我没有提供该模块,但从成员注入的方式,您想要提供的内容中应该清楚。

码:

 class ActorCreator implements Creator<MyActor>
   @Inject
   Injector injector;
   public MyActor create() {
     return injector.getInstance(MyActor.class);
   }
 }

 class MyActor extends AbstractActor {
   @Inject
   SomeController object;

   @Nullable
   MyDataObject data;

   public ReceiveBuilder createReceiveBuilder() {
    return receiveBuilder()
      .match(MyDataObject.class, m -> { /* doInitialize() */ })
      .build(); 
   }
}

class MyParentActor extends AbstractActor {
   @Inject
   ActorCreator creator;

   void createChild() {
     getContext().actorOf(new Props(creator));
   }

   void initializeChild(ActorRef child, MyDataObject obj) {
     child.tell(obj);
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.