【问题标题】:Custom Spring Bean Parameters自定义 Spring Bean 参数
【发布时间】:2014-11-17 15:06:41
【问题描述】:

我正在使用发布在 activator 上的 Spring Akka 示例来创建 Spring 托管 bean Actor。这是我目前正在使用的代码,包括一个演示类:

@Component
class Test extends UntypedActor {

    @Autowired
    protected ObjectMapper objectMapper;

    protected final Account account;
    protected final Order order;

    public Test(Account account, Order order) {
        this.account = account;
        this.order = order;
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof SomeCommand) {
            // Do something using the order and the account;
        } else if (message instanceof FooCommand) {
            // More stuff
        }
    }
}

@Component
public class SpringExtension extends AbstractExtensionId<SpringExtensionImpl> implements ExtensionIdProvider {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public SpringExtensionImpl createExtension(ExtendedActorSystem system) {
        return applicationContext.getBean(SpringExtensionImpl.class);
    }

    @Override
    public ExtensionId<? extends Extension> lookup() {
        return applicationContext.getBean(SpringExtension.class);
    }

}

@Component
public class SpringExtensionImpl implements Extension {

    @Autowired
    private ApplicationContext applicationContext;

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

}

public class SpringActorProducer implements IndirectActorProducer {

    private final ApplicationContext applicationContext;
    private final String actorBeanName;

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

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

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

}

现在我的问题是,如何使用自定义构造函数参数实例化一个演员。我曾考虑过使用工厂或设置方法,但我认为这不是一个选项,因为我相信底层的 Actor 类不可访问。非常感谢您对此事的任何意见。如果现在有什么清楚的,请发表评论。

PS。如果您认为我的代码中有错误或者有更好的解决方法,请告诉我!我对 Spring 和 Akka 的结合经验很少,因此不胜感激。

【问题讨论】:

  • 我的第一条评论是你的 UntypedActor 类应该有@Scope("prototype") 注释以及@Component。这是必需的,因为每次您请求 Spring 扩展创建这种类型的参与者时,您都希望它生成一个新实例。单例 bean 概念在这里不适用。
  • 要回答您的问题,根据经验,不可能混合创建演员的方法。要么所有依赖项都需要通过 Spring 注入,要么根本不需要,只需使用 Props 以标准 Akka 方式使用构造函数注入。以上面的示例为例,如果 Account 和 Order 以及 spring bean,那么您可以以与 ObjectMapper 相同的方式注入它们。或者,将 ObjectMapper 添加到您的构造函数参数中,并在创建此 Actor 的新实例时不使用 Spring 以这种方式注入它。
  • 只是补充一下,如果您的 Account 和 Order 实例是 Spring bean,那么您应该能够将 @Autowired 注释添加到构造函数以便它们也被注入。
  • 它们不是春豆。它们是使用 ORM 框架获得的。
  • 在这种情况下,我认为你被一种非 Spring 方法困住了来创建你的测试参与者的实例。您需要将 ObjectMapper 添加到构造函数参数并使用 Akka Props 以这种方式注入它。

标签: java spring akka


【解决方案1】:

您可以将附加参数作为可变参数 (Object...) 传递给 SpringExtensionImplSpringActorProducer。所以你的代码看起来像这样:

@Component
public class SpringExtensionImpl implements Extension {

   @Autowired
   private ApplicationContext applicationContext;

   public Props props(String actorBeanName, Object... args) {
       return (args != null && args.length > 0) ?
            Props.create(SpringActorProducer.class,
                    applicationContext,
                    actorBeanName, args) :
            Props.create(SpringActorProducer.class,
                    applicationContext,
                    actorBeanName);
    }
}

public class SpringActorProducer implements IndirectActorProducer {

    private final ApplicationContext applicationContext;
    private final String actorBeanName;
    private final Object[] args;

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

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

    @Override
    public Actor produce() {
        return args == null ? 
              (Actor) applicationContext.getBean(actorBeanName):
              (Actor) applicationContext.getBean(actorBeanName, args);
    }

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

}

然后您可以像这样创建您的测试参与者:

SpringExtensionImpl springExtensionImpl; actorSystem.actorOf(springExtensionImpl.create(Test.class, account, order));

【讨论】:

  • 记住 SpringExtensionImpl 在该行中创建 actor 将是实际对象,而不是类名,因为该类不是静态的。
猜你喜欢
  • 1970-01-01
  • 2013-03-03
  • 2011-02-02
  • 2014-11-23
  • 2020-08-15
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
相关资源
最近更新 更多