2017-03-22 106 views
1

我对戏的文档https://www.playframework.com/documentation/2.5.x/ScalaAkka阶打2.5和依赖注入演员

望着例子有点困惑,人们可以从一个控制器开始一个演员:

import play.api.mvc._ 
import akka.actor._ 
import javax.inject._ 

@Singleton 
class Application @Inject() (system: ActorSystem) extends Controller { 

    val actor = system.actorOf(Props(classOf[AnActor], "anActor") 

    //... 
} 

或者一个可以依靠在吉斯实例化的演员

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

import actors.ConfiguredActor 

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
     bindActor[AnActor]("anActor") 
    } 
} 

当演员是由吉斯实例化,可以注入的依赖进去

import akka.actor._ 
import javax.inject._ 
import play.api.Configuration 

class AnActor @Inject() (configuration: Configuration) extends Actor { 
    //... 
} 

然而,从控制器开始是演员引发

[IllegalArgumentException: no matching constructor found on class AnActor for arguments []] 

是否有办法注入一个服务到非吉斯实例化的演员?

+0

你可以在'Application'中注入'Configuration',然后将其作为参数提供吗?然后演员的创作就会成为'val actor = system.actorOf(Props(new AnActor(configuration)),“anActor”)' – Eric

+0

是的,这就是我现在所做的。但是,这看起来不太优雅。此外,我的最终目标是将服务注入到子actor中,并且我想避免将它们作为构造函数的参数传递给构造函数。 – david

+0

我明白了。我不确定这是否可行,但[AssistedInject](https://github.com/google/guice/wiki/AssistedInject)可能会有所帮助。 – Eric

回答

1

您可以使用bindActorFactory,然后使用工厂在控制器中创建角色。

绑定演员工厂。当你想要注入子actor时,并且想要将参数传递给它们,并且让Guice提供一些参数,这非常有用。

您在演员的随播对象中附近有一个工厂。

import akka.actor._ 

object AnActor { 

    trait Factory { 
    def apply(): Actor 
    } 
} 

class AnActor @Inject() (configuration: Configuration) extends Actor { 

    def receive = ??? 

} 

你在你的模块使用bindActorFactory

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

import actors._ 

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
    bindActorFactory[AnActor, AnActor.Factory] 
    } 
} 

然后,您可以用演员系统从你的控制器实例化你的角色(所以他们会的/用户的演员孩子的)和吉斯将尽魔法。

class LocationsController @Inject()(actorSystem: ActorSystem){ 

    def injectedChild2(create: => Actor, name: String, props: Props => Props = identity)(implicit system: ActorSystem): ActorRef = { 
    system.actorOf(props(Props(create)), name) 
    } 

    val actor1: ActorRef = injectedChild2(childFactory(),"anActor1")(actorSystem) 
    val actor2: ActorRef = injectedChild2(childFactory(),"anActor2")(actorSystem) 

} 

你可以添加参数Factory.apply如果你想通过不是由吉斯注入参数,在这种情况下,你需要@Assisted

object AnActor { 

    trait Factory { 
    def apply(someValue: String): Actor 
    } 
} 

class AnActor @Inject() (configuration: Configuration,@Assisted someValue: String) extends Actor { 

    def receive = ??? 

} 

class LocationsController @Inject()(actorSystem: ActorSystem){ 

    def injectedChild2(create: => Actor, name: String, props: Props => Props = identity)(implicit system: ActorSystem): ActorRef = { 
    system.actorOf(props(Props(create)), name) 
    } 

    val actor1: ActorRef = injectedChild2(childFactory("value fom actor 1"),"anActor1")(actorSystem) 
    val actor2: ActorRef = injectedChild2(childFactory("value from actor 2"),"anActor2")(actorSystem) 

} 

的例子来注释这个参数并且方法injectedChild2取自original Play example,但被修改为从控制器创建角色。

UPDATE:

检查this answer知道为什么你应该避免从控制器创建者,在詹姆斯罗珀的话。