【问题标题】:Java Akka Actors with parameters with Spring带有 Spring 参数的 Java Akka Actors
【发布时间】:2016-04-13 08:44:11
【问题描述】:

在我的项目中,我使用Lightbend activator template 作为代码库。它工作完美,但示例中的 Actor 不是使用参数创建的。

我需要创建一个新的 Actor 并在构造过程中向它传递一个参数,例如:

getContext().actorOf(SpringExtProvider.get(actorSystem).props("ControllerActor",type), "controller_" + type)

在这个用例中,控制器需要能够使用 props 参数 type 创建,该参数用于键入(显然)控制器。每个 Actor 都经过专门设计,可根据其类型处理和控制特定的对象王。

但是我不能在 props 方法中添加一个新参数来传递这个参数。它不工作。

这是我的代码:

SpringExtension.java

package com.orange.spectre.core.akka.configuration;

import akka.actor.AbstractExtensionId;
import akka.actor.ExtendedActorSystem;
import akka.actor.Extension;
import akka.actor.Props;
import com.orange.spectre.core.config.SpringActorProducer;
import org.springframework.context.ApplicationContext;

/**
 * Created by Hervé Darritchon on 04/04/2016.
 * <p>
 * An Akka Extension to provide access to Spring managed Actor Beans.
 */
public class SpringExtension extends AbstractExtensionId<SpringExtension.SpringExt> {

    /**
     * The identifier used to access the SpringExtension.
     */
    public static SpringExtension SpringExtProvider = new SpringExtension();

    /**
     * Is used by Akka to instantiate the Extension identified by this
     * ExtensionId, internal use only.
     */
    @Override
    public SpringExt createExtension(ExtendedActorSystem system) {
        return new SpringExt();
    }

    /**
     * The Extension implementation.
     */
    public static class SpringExt implements Extension {

        private volatile ApplicationContext applicationContext;

        /**
         * Used to initialize the Spring application context for the extension.
         *
         * @param applicationContext
         */
        public void initialize(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }

        /**
         * Create a Props for the specified actorBeanName using the
         * SpringActorProducer class.
         *
         * @param actorBeanName The name of the actor bean to create Props for
         * @return a Props that will create the named actor bean using Spring
         */
        public Props props(String actorBeanName) {
            return Props.create(SpringActorProducer.class,
                    applicationContext, actorBeanName);
        }

        public Props props(String actorBeanName, String type) {
            return Props.create(SpringActorProducer.class,
                    applicationContext, actorBeanName,type);
        }
    }
}

SpringActorProducer 包 com.orange.spectre.core.config;

import akka.actor.Actor;
import akka.actor.IndirectActorProducer;
import org.springframework.context.ApplicationContext;

/**
 * Created by Hervé Darritchon on 21/03/2016.
 */
public class SpringActorProducer implements IndirectActorProducer {

    private final ApplicationContext applicationContext;
    private final String actorBeanName;
    private final String type;

    public SpringActorProducer(ApplicationContext applicationContext,
                               String actorBeanName) {
        this.applicationContext = applicationContext;
        this.actorBeanName = actorBeanName;
        this.type = null;
    }

    public SpringActorProducer(ApplicationContext applicationContext,
                               String actorBeanName, String type) {
        this.applicationContext = applicationContext;
        this.actorBeanName = actorBeanName;
        this.type = type;
    }

    @Override
    public Actor produce() {
        return (Actor) applicationContext.getBean(actorBeanName);
    }

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

我无法创建带有 props 参数的演员,因为基本上可以使用 Akka (Documentation):

    public class DemoActor extends UntypedActor {

  /**
   * Create Props for an actor of this type.
   * @param magicNumber The magic number to be passed to this actor’s constructor.
   * @return a Props for creating this actor, which can then be further configured
   *         (e.g. calling `.withDispatcher()` on it)
   */
  public static Props props(final int magicNumber) {
    return Props.create(new Creator<DemoActor>() {
      private static final long serialVersionUID = 1L;

      @Override
      public DemoActor create() throws Exception {
        return new DemoActor(magicNumber);
      }
    });
  }

  final int magicNumber;

  public DemoActor(int magicNumber) {
    this.magicNumber = magicNumber;
  }

  @Override
  public void onReceive(Object msg) {
    // some behavior here
  }

}

  system.actorOf(DemoActor.props(42), "demo");

如果你能帮助我,那就太好了!

谢谢。

【问题讨论】:

  • 好问题;希望你的努力会有回报!
  • 如果您查看SpringActorProducer 中的代码,构造函数接受类型参数并将其存储在属性中,但是创建actor 的produce 方法不使用它。
  • 老实说,我不确定您所尝试的是否真的可行。通过将 Actor 创建委托给 Spring 容器,我的经验是您将对象注入 Actor 的方法必须使用 Spring 方法,即@Autowired。与其将类型注入到你的actor中以告知它可以处理哪种类型的对象,为什么不定义多个不同的actor来处理每个特定的对象类型呢?然后,您将对象路由到要处理的正确参与者

标签: java spring akka actor


【解决方案1】:

我同意“nickebbitt”。不确定这是否可能。其中一种方法是将幻数生成器的实现注入到actor中。 此外,我想建议以下 IndirectActorProducer 实现:

public class SpringDIActor implements IndirectActorProducer {

private static final Logger LOG = LoggerFactory.getLogger(SpringDIActor.class);

private Class<? extends Actor> type;
private Actor actorInstance = null;

public SpringDIActor(Class<? extends Actor> type) {
    this.type = type;
}

public SpringDIActor(Actor actorInstance) {
    this.actorInstance = actorInstance;
}

/**
 * This factory method must produce a fresh actor instance upon each
 * invocation. <b>It is not permitted to return the same instance more than
 * once.</b>
 */
@Override
public Actor produce() {
    Actor newActor = actorInstance;
    actorInstance = null;
    if (newActor == null) {
        try {
            newActor = type.newInstance();
        } catch (InstantiationException e) {
            LOG.error("Unable to create actor of type:{}", type, e);
        } catch (IllegalAccessException e) {
            LOG.error("Unable to create actor of type:{}", type, e);
        }
    }
    ApplicationContextProvider.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(newActor);
    return newActor;
}

/**
 * This method is used by [[Props]] to determine the type of actor which will
 * be created. This means that an instance of this `IndirectActorProducer`
 * will be created in order to call this method during any call to
 * [[Props#actorClass]]; it should be noted that such calls may
 * performed during actor set-up before the actual actor’s instantiation, and
 * that the instance created for calling `actorClass` is not necessarily reused
 * later to produce the actor.
 */
@Override
public Class<? extends Actor> actorClass() {
    return type;
}}

这允许您在不直接从任何代码访问 SpringContext 的情况下共同创建演员,如下所示:

ActorSystem.create("system").actorOf(Props.create(SpringDIActor.class, DemoActor.class))

然后只是在DemoActor中使用@Autowired注解。

不需要对 DemoActor 进行额外注释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    相关资源
    最近更新 更多