using guice injection with actor throws null pointer

大兔子大兔子 提交于 2019-12-01 04:49:44

You're getting the NullPointerException because Akka is instantiating your Retriever actor and not Guice. You need to get Guice to construct your instance and then pass that to Akka, IndirectActorProducer can help you achieve this, e.g.:

class RetrieverDependencyInjector implements IndirectActorProducer {
    final Injector injector;

    public RetrieverDependencyInjector(Injector injector) {
        this.injector = injector;
    }

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

    @Override
    public Retriever produce() {
        return injector.getInstance(Retriever.class);
    }
}

Note that produce() must create a new Actor instance each time it is invoked, it cannot return the same instance.

You can then get Akka to retrieve your actor through the RetrieverDependencyInjector, e.g.:

ActorRef myActor = Akka.system().actorOf(
    Props.create(RetrieverDependencyInjector.class, injector)
);

UPDATE

I thought about you comment further, you might be able to turn RetrieverDependencyInjector into a GenericDependencyInjector by providing the class of the Actor you want as a constructor parameter, that perhaps will allow you to do something like:

Props.create(GenericDependencyInjector.class, injector, Retriever.class)

I haven't tried this, but it might give you a starting point.

For anyone who needs this:

public class GuiceInjectedActor implements IndirectActorProducer {

final Injector injector;
final Class<? extends Actor> actorClass;

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

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

@Override
public Actor produce() {
    return injector.getInstance(actorClass);
}

}

AND

Akka.system().actorOf(Props.create(GuiceInjectedActor.class, INJECTOR,Retreiver.class))

Thats it...!!!

There can be other ways, eg, you can put a static injector handle in Boot or Some-Injector-Holder-class, and inject when you create the actor by call the inherited method: preStart ()

public class Retreiver extends UntypedActor {

    private Logger.ALogger log = Logger.of(Retreiver .class);

    @Override
    public void preStart () {
        super.preStart ();
        Boot.injector.injectMembers (this);
        //Some-Injector-holder.injectMembers (this);
    }

    @Inject
    private myDataService dataService;

    @Override
    public void onReceive(Object arg0) throws Exception {

        if (0 != dataService.getDataCount()) {
        ....
        ....
        ....
        }
    }

and also, you can also inject the injector in actor provider to initialize the actor by the injector in a scope of UntypedActorFactory:

public class InjectingActorProvider implements Provider<ActorRef> {
    @Inject
    private Injector injector;

    @SuppressWarnings("serial")
    @Override
    public final ActorRef get() {
            Props props = new Props(new UntypedActorFactory() {
                @Override
                public Actor create() {
                    return injector.getInstance(actorClass);
                }
            });

            props = props.withRouter(...);
            props = props.withDispatcher(...);
            actor = system.actorOf(props, actorName);
            return actor;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!