2016-04-13 9 views
5

In meinem Projekt habe ich als Code-Basis die Lightbend activator template verwendet. Es funktioniert perfekt, aber der Actor im Beispiel wird nicht mit Parametern erstellt.Java Akka Actors mit Parametern mit Spring

Ich brauche einen neuen Darsteller zu erstellen und er einen Parameter während der Bauphase passieren wie:

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

In diesem Anwendungsfall muss der Regler in der Lage sein, mit Requisiten paremeter Typ geschaffen werden welches benutzt wird um (offensichtlich) den Controller zu tippen. Jeder Aktor ist speziell darauf ausgelegt, einen bestimmten Objektkönig abhängig von seinem Typ zu handhaben und zu steuern.

Aber ich kann keinen neuen Parameter in der Requisiten-Methode hinzufügen, um diesen Parameter zu übergeben. Es funktioniert nicht.

Dies ist mein 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 Paket 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); 
    } 
} 

ich mit einem Requisite Parameter einen Schauspieler nicht schaffen kann, wie es im Grunde mit Akka wie (Documentation) möglich ist:

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"); 

Wenn Sie uns helfen können, soll es groß sein!

Danke.

+0

Nette Frage; Ich hoffe, Ihre Bemühungen werden sich auszahlen! – GhostCat

+0

Wenn Sie den Code in 'SpringActorProducer' überprüfen, akzeptiert der Konstruktor den Typparameter und speichert ihn in der Eigenschaft, aber die' product' Methode, die den Actor erstellt, verwendet sie nicht. – nickebbitt

+0

Um ehrlich zu sein, bin ich mir nicht sicher, ob das, was Sie versuchen, wirklich möglich ist. Durch die Delegierung der Actor-Erstellung an den Spring-Container besteht meine Erfahrung darin, dass Ihr Ansatz, Objekte in Ihren Actor zu injizieren, den Spring-Ansatz verwendet, d. H. "@ Autowired". Anstatt den Typ in Ihren Akteur zu injizieren, um ihn darüber zu informieren, welche Art von Objekten er verarbeiten kann, warum definieren Sie nicht mehrere Akteure, die mit jedem spezifischen Objekttyp umgehen sollen? Dann leiten Sie Ihre Objekte an den richtigen Akteur weiter, der bearbeitet werden soll – nickebbitt

Antwort

2

Ich bin mit "nickebbitt" einverstanden. Nicht sicher, dass es möglich ist. Und eine der Möglichkeiten besteht darin, dem Schauspieler eine Implementierung des magischen Zahlengenerators zu injizieren. Darüber hinaus wouldlike ich folgende IndirectActorProducer Implementierung vorschlagen:

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

Auf diese Weise können Sie wie folgt zusammen aus einem beliebigen Code auf SpringContext ohne direkte accesing Akteure schaffen:

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

Dann @Autowired Anmerkung in verwenden, nur der DemoActor.

Keine zusätzliche Anmerkung zu DemoActor ist nicht erforderlich.

Verwandte Themen