Java Akka Actors with Spring Options

In my project, I used the Lightbend activator template as the code base. It works great, but as an example, a character with parameters is not created.

I need to create a new Actor and pass it a parameter during construction, for example:

getContext().actorOf(SpringExtProvider.get(actorSystem).props("ControllerActor",type), "controller_" + type) 

In this case, the controller must be created using the repository of the paremeter type , which is used to input the (obviously) controller. Each actor is specifically designed to process and manage the specific king of an object, depending on its type.

But I can’t add a new parameter in the props method to pass this parameter. He does not work.

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 cannot create an actor with a props parameter, since this is mainly possible with Akka ( 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 * (eg 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, this should be great!

Thanks.

+5
source share
1 answer

I agree with "nickebbitt". Not sure if he is calm. And one way is to inject a magic number into the generator. In addition, I would like to suggest the following implementation of IndirectActorProducer:

 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 to create participants without directly accessing SpringContext from any code as follows:

 ActorSystem.create("system").actorOf(Props.create(SpringDIActor.class, DemoActor.class)) 

Then just use the @Autowired annotation in the DemoActor.

No additional annotation is required on DemoActor.

+2
source

Source: https://habr.com/ru/post/1247019/


All Articles