2016-06-11 14 views
2

同じ親アクターの複数のインスタンスを作成できますが、異なる子アクターを使用したいと考えています。私はこれがGuiceと可能でなければならないと考えていますが、私は解決策を見出していません。ここでScala/Akka/Guiceは子アクタを動的に注入します

は私が考えているものです〜

コントローラー:

class Application @Inject()(@Named(ParentActor.parentActor1) parentActor1: ActorRef, 
         @Named(ParentActor.parentActor2) parentActor2: ActorRef) 
    extends Controller { 

    def index = Action { 
    parentActor1 ! "Message" 
    parentActor2 ! "Message" 
    Ok() 
    } 
} 

親俳優:

object ParentActor { 
    final val parentActor1 = "parentActor1" 
    final val parentActor2 = "parentActor2" 
} 

class ParentActor @Inject() (childActor: ActorRef) extends Actor { 

    def receive = { 
    case "Message" => 
     println(s"ParentActor ${self.path} received message...") 
     childActor ! "Message" 
    } 
} 

子役のA:

class ChildActorA extends Actor { 

    def receive = { 
    case "Message" => 
     println("ChildActorA received message...") 
    } 
} 

子役のB:

class ChildActorB extends Actor { 

    def receive = { 
    case "Message" => 
     println("ChildActorB received message...") 
    } 
} 

モジュール:

class Modules extends AbstractModule with AkkaGuiceSupport { 

    override def configure() = { 
    bindActor[ParentActor](ParentActor.parentActor1) 
    bindActor[ParentActor](ParentActor.parentActor2) 
    } 
} 

私は "parentActor1は" ChildActorAのインスタンスにその "childActorの" 参照ポイントを持っている持っているしたい場合と "parentActor2"はChildActorBのインスタンスを参照する "childActor" refを持っていますか? Guiceとこれを達成することは可能ですか?

+0

を使用することができることを考えているがあなたの代わりに '' ActorRef'のProps'を注入しようとしましたか? – Sergey

+0

@Sergey少し詳しく説明できますか? – Nick

+0

私は、「導入」と呼ばれるものを使用することで、ParentActorが適切な子アクターに「導入」されるという代替ソリューションがあると思います。たとえば、私のコントローラは、 "childActor"が適切な子アクタ(ChildActorAまたはChildActorBのいずれか)へのActorRefである "Message(childActor)"のようなParentActorにメッセージを送信します。 – Nick

答えて

3

私はプレイを使用していない似たような

を達成するためにhttps://github.com/rocketraman/activator-akka-scala-guiceに基づいていくつかのコードを使用していますので、私はGuiceのを初期化し、そこのGuiceを初期化するには俳優のシステム

import akka.actor._ 
import javax.inject.{Inject, Provider, Singleton} 
import com.google.inject.AbstractModule 
import net.codingwell.scalaguice.InjectorExtensions._ 
import com.google.inject.Guice 
import com.google.inject.Injector 
import scala.concurrent.Await 
import scala.concurrent.duration.Duration 

object Bootstrap extends App { 

    val injector = Guice.createInjector(
    new AkkaModule(), 
    new ServiceModule() 
) 

    implicit val system = injector.instance[ActorSystem] 

    val parentActor1 = system.actorOf(ParentActor.props(ChildActorA.name)) 
    val parentActor2 = system.actorOf(ParentActor.props(ChildActorB.name)) 


    parentActor1 ! "Message" 
    parentActor2 ! "Message" 

    system.terminate() 

    Await.result(system.whenTerminated, Duration.Inf) 
} 

をブートストラップする必要があります

つ拡張を初期化し、

import akka.actor.ActorSystem 
import AkkaModule.ActorSystemProvider 
import com.google.inject.{AbstractModule, Injector, Provider} 
import com.typesafe.config.Config 
import net.codingwell.scalaguice.ScalaModule 
import javax.inject.Inject 

object AkkaModule { 

    class ActorSystemProvider @Inject() (val injector: Injector) extends Provider[ActorSystem] { 

    override def get() = { 

     val system = ActorSystem("actor-system") 

     GuiceAkkaExtension(system).initialize(injector) 

     system 
    } 
    } 
} 

class AkkaModule extends AbstractModule with ScalaModule { 

    override def configure() { 
    bind[ActorSystem].toProvider[ActorSystemProvider].asEagerSingleton() 
    } 

} 
0を必要アクターシステムを注入する2つのクラス/オブジェクトであります

子供

import javax.inject.Inject 

import akka.actor.{Actor, ActorRef, ActorSystem} 
import com.google.inject.name.{Named, Names} 
import com.google.inject.{AbstractModule, Provides, Singleton} 
import net.codingwell.scalaguice.ScalaModule 

class ServiceModule extends AbstractModule with ScalaModule with GuiceAkkaActorRefProvider { 

    override def configure() { 
    bind[Actor].annotatedWith(Names.named(ChildActorA.name)).to[ChildActorA] 
    bind[Actor].annotatedWith(Names.named(ChildActorB.name)).to[ChildActorB] 
    } 

    @Provides 
    @Named(ChildActorA.name) 
    def provideChildActorARef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, ChildActorA.name) 

    @Provides 
    @Named(ChildActorB.name) 
    def provideChildActorBRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, ChildActorB.name) 

} 

延長

import akka.actor._ 
import com.google.inject.Injector 

class GuiceAkkaExtensionImpl extends Extension { 

    private var injector: Injector = _ 

    def initialize(injector: Injector) { 
    this.injector = injector 
    } 

    def props(actorName: String) = Props(classOf[GuiceActorProducer], injector, actorName) 

} 

object GuiceAkkaExtension extends ExtensionId[GuiceAkkaExtensionImpl] with ExtensionIdProvider { 

    override def lookup() = GuiceAkkaExtension 

    override def createExtension(system: ExtendedActorSystem) = new GuiceAkkaExtensionImpl 

    override def get(system: ActorSystem): GuiceAkkaExtensionImpl = super.get(system) 

} 

trait NamedActor { 
    def name: String 
} 

trait GuiceAkkaActorRefProvider { 

    def propsFor(system: ActorSystem, name: String) = GuiceAkkaExtension(system).props(name) 

    def provideActorRef(system: ActorSystem, name: String): ActorRef = system.actorOf(propsFor(system, name)) 

} 

プロデューサー

import akka.actor.{IndirectActorProducer, Actor} 
import com.google.inject.name.Names 
import com.google.inject.{Key, Injector} 

class GuiceActorProducer(val injector: Injector, val actorName: String) extends IndirectActorProducer { 

    override def actorClass = classOf[Actor] 

    override def produce() = injector.getBinding(Key.get(classOf[Actor], Names.named(actorName))).getProvider.get() 

} 

とあなたの俳優のためのプロバイダを作成するには、別の1

import javax.inject.Inject 
import akka.actor._ 


object ParentActor { 

    def props(childName: String)(implicit @Inject() system: ActorSystem) = Props(classOf[ParentActor],system.actorOf(GuiceAkkaExtension(system).props(childName))) 

} 

class ParentActor (childActor: ActorRef) extends Actor { 

    def receive = { 
    case "Message" => 
     println(s"ParentActor ${self.path} received message...") 
     childActor ! "Message" 
    } 
} 

object ChildActorA extends NamedActor{ 

    override final val name = "ChildActorA" 
    def props() = Props(classOf[ChildActorA]) 

} 

class ChildActorA extends Actor { 

    def receive = { 
    case "Message" => 
     println("ChildActorA received message...") 
    } 
} 

object ChildActorB extends NamedActor{ 

    override final val name = "ChildActorB" 
    def props() = Props(classOf[ChildActorB]) 

} 


class ChildActorB extends Actor { 

    def receive = { 
    case "Message" => 
     println("ChildActorB received message...") 
    } 
} 
あなたが明示的に子供に名前を付ける必要がありSBT

> run 
[info] Running Bootstrap 
ParentActor akka://actor-system/user/$b received message... 
ParentActor akka://actor-system/user/$d received message... 
ChildActorB received message... 
ChildActorA received message... 
[success] Total time: 1 s, completed Jun 14, 2016 1:23:59 AM 

から

出力、

それは純粋なまたは最もエレガントな答えはありません、と私は、コードを最適化することができると確信していますが、それはあなたがすることができます同じ子と異なる子を持つインスタンスを作成します。

私はあなたにもBindingAnnotations

+0

徹底的な答えをありがとう!私が自由な瞬間を得たときにこれを試してみましょう。私はあなたに戻ってきます... – Nick

+0

確かに!これはあなたのために働いた場合私に教えてください – motilio

関連する問題