Martijn Martijn - 2 months ago 14
Java Question

Custom Spring Bean Parameters

I'm using the Spring Akka example posted on activator to create Spring managed bean actors. This is the code I'm currently using including a demo class:

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

}


Now my question is, how do instantiate an actor with custom constructor arguments. I have thought about using a factory or setter methods but I don't think this is an option since the underlying Actor class is not accessible I believe. Any input on this matter is greatly appreciated. If something is now clear, please post a comment.

PS. If you believe my there is an error in my code or there is a better way of going about it, please do tell me! I have little experience with Spring and Akka combined so any advice is appreciated.

Answer

You could pass the additional arguments as varargs (Object...) to SpringExtensionImpl and SpringActorProducer. So your code would look like this:

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

}

You can then create your Test actor like this:

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

Comments