PROBLEM
To create Spring-managed prototype-scoped actors.
SOLUTION
The key to this solution is to create a custom implementation of IndirectActorProducer
. From the documentation:-
“…This interface defines a class of actor creation strategies deviating from the usual default of just reflectively instantiating the Actor subclass. It can be used to allow a dependency injection framework to determine the actual actor class and how it shall be instantiated…”
First, create an implementation of IndirectActorProducer
that creates the actor using Spring’s ApplicationContext
.
public final class SpringActorProducer implements IndirectActorProducer { private final ApplicationContext applicationContext; private final Class<? extends Actor> actorClass; public SpringActorProducer(final ApplicationContext applicationContext, final Class<? extends Actor> actorClass) { this.applicationContext = applicationContext; this.actorClass = actorClass; } @Override public Actor produce() { return applicationContext.getBean(actorClass); } @Override public Class<? extends Actor> actorClass() { return actorClass; } }
To prevent tedious auto-wiring ApplicationContext
in every actor class to be passed to SpringActorProducer
above, create a Spring-managed service that will do just that.
@Component public final class SpringProps { private final ApplicationContext applicationContext; @Autowired public SpringProps(final ApplicationContext applicationContext) { this.applicationContext = applicationContext; } public Props create(final Class<? extends Actor> actorClass) { return Props.create(SpringActorProducer.class, applicationContext, actorClass); } }
Now, instead of creating the actors like this….
ActorRef master = actorSystem.actorOf( Props.create(Master.class), "master"); ActorRef workerRouter = getContext().actorOf( Props.create(Worker.class) .withRouter(new RoundRobinPool(5)), "workerRouter");
… we will use the auto-wired SpringProps
to create the actors…
@Autowire private SpringProps springProps; ... ActorRef master = actorSystem.actorOf( springProps.create(Master.class), "master"); ActorRef workerRouter = getContext().actorOf( springProps.create(Worker.class) .withRouter(new RoundRobinPool(5)), "workerRouter");
Make sure all actor classes are Spring-managed with prototype-scoped by annotating them with @Component
and @Scope("prototype")
.
To see the full example, visit https://github.com/choonchernlim/test-akka-spring