【问题标题】:Play 2.4 - How to inject akka actors using guicePlay 2.4 - 如何使用 guice 注入 akka actor
【发布时间】:2016-02-26 15:10:50
【问题描述】:

如何在 Play 2.4 中创建一个 Actor 以便它使用 Guice 自动注入依赖项?我阅读了几篇他们使用 GuiceApplicationBuilder 然后创建演员的帖子。我不想控制播放应用程序的实例化方式。相反,我只想知道如何创建一个演员实例,以便使用 Guice 管理依赖项。

创建一个有 5 个工人的 RoundRobinRouter

class RouterActor extends Actor with ActorLogging {
  val router = {
    val routees = Vector.fill(5) {
      val r = context.actorOf(Props[Worker])
      context watch r
      ActorRefRoutee(r)
    }
    Router(RoundRobinRoutingLogic(), routees)
  }

  def receive = {
    case job: Job =>
    router.route(job, sender())
  }
}

扩展 AkkaGuiceSupport 并创建一个绑定 RouterActor 的模块

class RouterActorModule extends AbstractModule with AkkaGuiceSupport {
  override def configure() = {
    bindActor[RouterActor]("router-manager")
  }
}

根据RouterModule中actor的名字使用guice DI注入RouterActor

class ScheduledReportGenerationService @Inject() (@Named("router-manager") serviceRouter: ActorRef) extends Actor {
  def receive = {
    case serviceInfo: ServiceContext => submitJobs(serviceInfo)
  }

  def submitJobs(serviceInfo: ServiceContext) = {
    serviceRouter ? serviceInfo
  }
}

如何初始化 ScheduledReportGenerationService Actor,以便 Guice 自动注入 RouterActor?我收到以下错误

java.lang.IllegalArgumentException: no matching constructor found on class vistoscheduler.ScheduledReportGenerationService for arguments []

我了解 system.actorOf 使用 Akka 创建 Actor,因此 Guice 无法注入依赖项。文档不是很清楚,我无法解决这个问题。

class SchedulerBootStrap extends Actor {
  implicit val system = context.system
  implicit val timeout = Timeout(5.minute)

  def receive = {
    case "BOOTSTRAP_SCHEDULER" => bootStrapServices()
  }

  def bootStrapServices() = {
    lazy val scheduledReportGenerationService =    system.actorOf(Props[ScheduledReportGenerationService], "scheduled-reports-service-actor")
    scheduledReportGenerationService ? ServiceContext(1L)
  }
}

【问题讨论】:

  • 您是否在 conf 中启用了您的模块,例如 play.modules.enabled += "packagename.RouterActorModule"

标签: playframework-2.0 akka guice


【解决方案1】:

你可以使用IndirectActorProducer

class GuiceActorProducer(val injector: play.inject.Injector, val cls: Class[_ <: Actor]) extends IndirectActorProducer {

  override def actorClass = classOf[Actor]

  override def produce() = {
    injector.instanceOf(cls)
  }

}

并创建您的服务,例如,

val scheduledReportGenerationService = system.actorOf(Props(classOf[GuiceActorProducer], injector, classOf[ScheduledReportGenerationService]))

只要确保您使用的是play.inject.Injector

编辑以添加工作代码,使用com.google.inject.Injector

class Application @Inject() (injector: Injector, system: ActorSystem) extends Controller {

  def index = Action { request =>
    val scheduledReportGenerationService = system.actorOf(Props(classOf[GuiceActorProducer], injector, classOf[ScheduledReportGenerationService]))
    scheduledReportGenerationService ! "some"
    Ok(views.html.index("Your new application is ready."))
  }

}

class RouterActor extends Actor with ActorLogging {
  def receive = {
    case x: String =>
      log.info(x)
  }
}

class ScheduledReportGenerationService @Inject() (@Named("router-manager") serviceRouter: ActorRef) extends Actor {
  implicit val timeout = Timeout(5.minute)
  def receive = {
    case serviceInfo: String => submitJobs(serviceInfo)
  }

  def submitJobs(serviceInfo: String) = {
    log.info("service")
    serviceRouter ? serviceInfo
  }
}

class RouterActorModule extends AbstractModule with AkkaGuiceSupport {
  override def configure() = {
    bindActor[RouterActor]("router-manager")
  }
}



class GuiceActorProducer(val injector: Injector, val cls: Class[_ <: Actor]) extends IndirectActorProducer {

  override def actorClass = cls

  override def produce() = {
    injector.getInstance(cls)
  }
}

还有另一种方法可以使用 akka Extension。见this project

【讨论】:

  • 在语句val scheduleReportGenerationService = system.actorOf(Props(classOf[GuiceActorProducer], injector, classOf[ScheduledReportGenerationService]))中,如何获取play.inject.Injector的实例?
  • playframework.com/documentation/2.4.2/api/java/play/inject/… 说我们应该使用 play 底层依赖注入(Guice)。另外,无论如何,我也无法注入 play.inject.Injector 。你能帮忙吗?
  • 如何使用此方法提供辅助参数?例如,如果 ScheduledReportGenerationService 有一个具有 3 个注入参数和 2 个辅助参数的工厂,我如何将它们传递给 Props 函数?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 2015-12-16
  • 2016-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多