【问题标题】:using guice injection with actor throws null pointer对actor使用guice注入会抛出空指针
【发布时间】:2013-07-10 20:24:12
【问题描述】:

我在作为 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 为空。请在这方面给我建议。

谢谢。

【问题讨论】:

  • 请注意,我对此没有任何绑定。当 Retreiver 类被创建为演员时,我希望 guice 注入 dataService。

标签: java dependency-injection guice akka actor


【解决方案1】:

还可以有其他方式,比如你可以在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;
    }
}

【讨论】:

  • 注射器是怎么注射的?
  • 注入器由Guice提供,无需注入。
【解决方案2】:

对于有需要的人:

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

就是这样...!!!

【讨论】:

  • 如何将它与提供者注入一起使用?通常在我的 GuiceModule 中,我有这样的功能:@Provides @Named("somename") ActorRef getSomeActor() { return Akka.System()... } 问题是我无法从 GuiceModule 内部访问 Injector。
  • @Chanan The Injector can also be injected into your module, like this: @Provides @Singleton @Named("jcrActor") ActorSelection jcrActor(final ActorSystem system, final Injector injector) throws Exception { system.actorOf(new RoundRobinPool(3).props(Props.create(GuiceInjectedActor.class, injector, JcrActor.class)), "jcrActorRouter"); return system.actorSelection(ActorConstants.PATH_JCR_ACTOR_ROUTER); }
【解决方案3】:

你得到了 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)
);

更新

我考虑过您进一步评论,您可以通过提供您想要的 Actor 的类作为构造函数参数,将 RetrieverDependencyInjector 转换为 GenericDependencyInjector,这可能允许您执行以下操作:

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

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

【讨论】:

  • 乔纳森,感谢您的回答。我有很多没有类型的演员。所以我需要一个通用的依赖注入器来检索演员。我该怎么做?
  • 谢谢乔纳森,很有帮助。
  • 如何将它与提供者注入一起使用?通常在我的 GuiceModule 中,我有这样的功能:@Provides @Named("somename") ActorRef getSomeActor() { return Akka.System()... } 问题是我无法从 GuiceModule 内部访问 Injector。
  • 为什么到处都在使用injector?我唯一拥有它的地方是我的Global.java,它是私人的,所以这很令人困惑。
猜你喜欢
  • 2012-10-29
  • 1970-01-01
  • 2016-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多