我对播放文档https://www.playframework.com/documentation/2.5.x/ScalaAkka
有点困惑查看示例,可以从控制器启动一个actor:
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")
//...
}
或者可以依靠Guice来实例化那个演员
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")
}
}
当演员被Guice实例化时,可以向其中注入依赖
import akka.actor._
import javax.inject._
import play.api.Configuration
class AnActor @Inject() (configuration: Configuration) extends Actor {
//...
}
但是,从控制器启动该actor会引发
[IllegalArgumentException: no matching constructor found on class AnActor for arguments []]
有没有办法将服务注入非Guice实例化的actor?
答案 0 :(得分:1)
您可以使用bindActorFactory然后使用工厂在控制器中创建actor。
绑定演员工厂。当你想要注入子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]
}
}
然后,你可以使用actor系统从你的控制器中实例化你的actor(所以他们将成为/ user actor的孩子)并且guice会发挥其魔力。
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)
}
如果您想传递未由guice注入的参数,可以向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,但已修改为从控制器创建actor。
<强>更新强>
检查this answer以了解为什么你应该避免使用控制器创建演员,用James Roper的话说。