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
Leave a Reply