首页 文章

玩2.4 - 如何使用guice注入akka actor

提问于
浏览
0

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

创建一个包含5个worker的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)
  }
}

1 回答

  • 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 .

    Edit to add the working codecom.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 .

相关问题