2016-06-11 147 views
2

我希望能够创建同一个父演员的多个实例,但与不同的子演员。我认为这与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" 
    } 
} 

儿童演员答:

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” 有有它的 “childActor” 参考点ChildActorA的实例和“parentActor2”使其“childActor”引用指向ChildActorB的一个实例?这可能与Guice实现吗?

+0

你尝试注入的'Props'代替'ActorRef'? – Sergey

+0

@谢谢你能详细一点吗? – Nick

+0

我想一个替代解决方案是使用我认为被称为“介绍”的方法,即将ParentActor“引入”适当的儿童演员。例如,我的控制器会向ParentActor发送一条消息,如“Message(childActor)”,其中“childActor”是适当的子actor(ChildActorA或ChildActorB)的ActorRef。 – Nick

回答

3

我使用基于https://github.com/rocketraman/activator-akka-scala-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演员系统

另一个创建提供商为孩子

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 

你必须明确地命名的孩子,

这不是最纯粹的或者最优雅的答案,而且我敢肯定,代码可以优化,但它可以让你用不同的孩子创建同一父母的实例。

我在想,你也可以使用BindingAnnotations

+0

感谢您的彻底解答!让我测试一下,当我得到一个自由的时刻,我会回到你身边...... – Nick

+0

当然!让我知道这是否适合你 – motilio