2016-06-11 8 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"참조가 있어야합니까? 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) 
} 

을 Guice을 초기화하고 부트 스트랩해야

비슷한 달성하기 위해 https://github.com/rocketraman/activator-akka-scala-guice에 따라 몇 가지 코드를 사용하고

+0

당신이'Props' 대신'ActorRef'의 주입을 시도 했 BindingAnnotations을 사용할 수 있다는 생각 해요? – Sergey

+0

@Sergey 당신은 약간 정교 할 수 있 었는가? – Nick

+0

나는 하나의 대체 솔루션이 "소개"라고 불리는 것을 사용하는 것이 겠지요. 그러면 ParentActor가 적절한 하위 배우에게 소개 될 것입니다. 예를 들어, 내 컨트롤러는 "childActor"가 적절한 하위 액터 (ChildActorA 또는 ChildActorB)에 대한 ActorRef 인 "Message (childActor)"와 같은 ParentActor에 메시지를 보냅니다. – Nick

답변

3

한 확장을 초기화

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 필요 액터 시스템을 주입하는 두 클래스/개체

아이들

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() 

} 

과 배우의 제공을 만들 수있는 또 하나

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 
당신은 명시 적으로 아이의 이름을 가지고

,

그것은 아니에요 순수한 또는 가장 우아한 대답, 나는 코드를 최적화 할 수 있습니다 확신 해요,하지만 당신을 수 있습니다 다른 아이를 가지는 같은 부모의 인스턴스를 생성합니다.

난 당신이 또한

+0

철저한 답변 주셔서 감사합니다! 내가 자유로운 순간을 얻었을 때 나는 이것을 시험해 봅니다. 그리고 나는 당신에게 돌아갈 것입니다 ... – Nick

+0

그래! 이게 너에게 효과가 있는지 알려줘. – motilio

관련 문제