我希望能够创建同一父actor的多个实例,但具有不同的子actor。我认为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"拥有它的" childActor" ref指向ChildActorA的实例和" parentActor2"拥有" childActor" ref指向ChildActorB的一个实例?这可以用Guice实现吗?
答案 0 :(得分:3)
我正在使用一些基于https://github.com/rocketraman/activator-akka-scala-guice的代码来完成类似的事情
我没有使用Play,所以我必须初始化Guice并引导actor系统
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,有两个类/对象:
初始化扩展并在必要时注入actor系统
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()
}
}
另一个为孩子们创建提供者
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