使用guice注入与actor抛出空指针

时间:2013-07-12 10:06:16

标签: java dependency-injection guice akka actor

我在服务器的字段注入时获得空指针异常,该服务器以akka actor的形式启动。

计划部分:

private ActorRef myActor = Akka.system().actorOf(
        new Props(Retreiver.class));

@Override
public void onStart(Application app) {
    log.info("Starting schedular.....!");
    Akka.system()
            .scheduler()
            .schedule(Duration.create(0, TimeUnit.MILLISECONDS),
                    Duration.create(30, TimeUnit.MINUTES), myActor, "tick",
                    Akka.system().dispatcher());

}

Retreiver类部分:

public class Retreiver extends UntypedActor {

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

@Inject
private myDataService dataService;

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

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

}

我为dataService获取null。请告诉我这个。

感谢。

3 个答案:

答案 0 :(得分:8)

对于任何需要此功能的人:

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);
}

}

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

多数民众赞成...... !!!

答案 1 :(得分:7)

你得到NullPointerException因为Akka正在实例化你的Retriever演员,而不是Guice。您需要让Guice构建您的实例,然后将其传递给Akka,IndirectActorProducer可以帮助您实现此目的,例如:

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);
    }
}

请注意produce() 必须每次调用时都会创建一个新的Actor实例,它不能返回相同的实例。

然后,您可以让Akka通过RetrieverDependencyInjector检索您的演员,例如:

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

<强>更新

我考虑过你进一步评论,你可以通过提供你想要的RetrieverDependencyInjector类作为构造函数参数来将GenericDependencyInjector变成Actor,这可能会允许你可以这样做:

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

我没试过这个,但它可能会给你一个起点。

答案 2 :(得分:2)

可以有其他方法,例如,您可以在Boot或Some-Injector-Holder-class中放置静态注入器句柄,并在通过调用继承方法创建actor时注入: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()) {
        ....
        ....
        ....
        }
    }

并且,您还可以在actor提供程序中注入注入器,以通过UntypedActorFactory范围内的注入器初始化actor:

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;
    }
}