In my project, I have used as a code base the Lightbend activator template. It works perfect but the Actor in example is not created with parameters.
I need to create a new Actor and pass to it a parameter during construction such as :
getContext().actorOf(SpringExtProvider.get(actorSystem).props("ControllerActor",type), "controller_" + type)
In this use case, the controller needs to be able to be created with a props paremeter type which is used to typed (obviously) the controller. Each Actor is specifically design to handle and control a specific king of object depending on its type.
But I can't add a new parameter in the props method to pass this parameter. It is not working.
This is my code :
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 package 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);
}
}
I can't create an actor with a props parameter as it is possible basically with Akka like (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");
If you can help me, it should be great !
Thanks.
I'm agree with "nickebbitt". Not sure that it is spossible. And one of the way is to inject an implementation of magic number generator into the actor. Furthermore, I wouldlike to suggest following IndirectActorProducer implementation:
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;
}}
This allows you co create actors without direct accesing to SpringContext from any code as follows:
ActorSystem.create("system").actorOf(Props.create(SpringDIActor.class, DemoActor.class))
Then just to use @Autowired annotation into the DemoActor.
No additional annotation on DemoActor is not required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With