【问题标题】:Using a WebService with Akka Actors and the play framework将 WebService 与 Akka Actors 和 play 框架一起使用
【发布时间】:2016-10-17 15:10:37
【问题描述】:

我已经使用 Play 和 Akka 构建了一个 Web 服务,现在需要集成另一个 Web 服务,我的 Web 服务是一个客户端。

我的默认控制器(带有关联的路由文件)看起来像

class myController @Inject() (implicit val messagesApi: MessagesApi, 
    config: play.api.Configuration) extends Controller with I18nSupport  {
// Actions
}

这启动了一个大型演员系统,一切都很好。

其中一个actor定义如下 -

class ActorMgr  ( jobId: Long, 
    config: Config) extends Actor  with ActorLogging {
// Actor specific stuff
}

我的问题是我现在需要从这个演员那里调用一个新的网络服务。此 Web 服务是一个数据库,将记录此参与者的结果。

我已经看到并遵循了(以及其他人)的指示

  1. https://playframework.com/documentation/2.5.x/ScalaWS
  2. Dependency injection with abstract class and object in Play Framework 2.5

按照上面的说明,我应该将 WSClient 注入到我需要访问它的类中。

我能够解决依赖注入到第二个控制器中,如下所示

class DbController @Inject() (ws: WSClient) extends Controller {  
  def post = Action { 
         // access webservice
  }
}

这行得通,我可以通过访问路由文件中映射到的 URL 来执行“发布”操作,从而访问 Web 服务。我现在也有两个控制器。

我的问题是从 ActorMgr(一个 Akka Actor)访问 Web 服务控制器“post”方法。我该如何启用它?

【问题讨论】:

  • 你可以使用依赖注入来创建actor,见这里:playframework.com/documentation/2.5.x/…
  • Haspemulator,感谢您的回复。它回答了我最初的部分问题(我如何依赖注入到演员中),但没有解决我的问题。我重新整理了我的部分问题,以便更清楚。
  • 这是 a finally 所做的,

标签: scala playframework dependency-injection akka guice-3


【解决方案1】:

经过大量研究,我想在这里更新我的发现。虽然我能够解决我的具体问题如下,这里还有很多要说的。

我的具体解决办法先-

代替 DbController,我将我的服务包装如下,并在需要的地方注入它 -

trait Db {
  def post
}

class InfluxDb @Inject() (ws: WSClient) extends Db  {
  val logger = LoggerFactory.getLogger(classOf[InfluxDb])
  logger.info("InfluxDb: Initiatlized")     

  def post = { 


    val req = ws.url("http://localhost:9086/write")
                .withQueryString("db" -> "db1")
                .withHeaders("Content-Type" -> "application/json")
                .post("job_id,command=PUT value=99")

    logger.debug("InfluxDb: Post")     
    }
}

话虽如此,注入东西给我带来了很多问题。我终于意识到这里有一些不同的用例 -

  1. 使用 Akka 和 Guice,而不使用 Playframework
  2. 使用 Playframework + Akka + Guice 并注入顶级actor
  3. 使用 Playframework + Akka + Guice 并注入子actor
  4. 使用 playframework + Akka + Guice 但创建不是“注入”您的顶级演员和演员系统。

您将如何解决上述每个问题。

  1. 对于 (1) - 请参阅 guice akka tutorial
  2. 对于 (2) 和 (3) - 请参阅 Playframework Documentation
  3. 对于 (4) 这有点棘手

您需要扩展“IndirectActorProducer”,然后使用它来创建您的 ActorRef。问题是“道具”不知道如何与 Guice 交互。这也是(1)中解决方案的一部分

下面的示例代码显示了所有 4 个用例,并进行了编译。在下面的代码中

ParentActor - 参考上述用例 (2),ChildActor 参考用例 (3),ParentActor_2 和 ChildActor_2 参考用例 (4)。

 // play imports
import play.api.mvc._
import play.api.Logger
import play.api.mvc.Results

// actor imports
import akka.actor.{Actor, ActorSystem, ActorRef,   Props, IndirectActorProducer}

// DI imports
import com.google.inject.{Injector, AbstractModule, Key, Provides}
import javax.inject._
import com.google.inject.assistedinject.Assisted
import play.libs.akka.AkkaGuiceSupport
import play.api.libs.concurrent.InjectedActorSupport


class MainCntrlr @Inject() (injector : Injector, 
                            @Named("PActor") pa: ActorRef,
                            cfP: ParentActor_2.Factory) 
                            extends Controller {
  Logger.debug("MainCntrlr: created")    

  val pa_2 = ActorSystem("test")
               .actorOf(Props(classOf[GuiceActorProducer], injector, "PActor_2"), "PA_2")  

  pa   ! 12               
  pa_2 ! 100

  def index          = Action {  Ok (views.html.index.render()) }
}


class ParentActor @Inject() (cf: ChildActor.Factory) extends Actor with InjectedActorSupport {
  Logger.debug("ParentActor: created")
  val cactor = injectedChild(cf(2),"childActor")
  cactor ! 10

  def receive = { case _ => Logger.debug("ParentActor received msg") } 
}


object ChildActor { trait Factory { def apply(i: Int) : Actor } }
class  ChildActor @Inject()( i: Injector, @Assisted v: Int) extends Actor {
  Logger.debug("ChildActor: created with value " + v.toString)

  def receive = { case _ => Logger.debug("ChildActor received msg") } 
}

class ParentModule extends AbstractModule with AkkaGuiceSupport {
  def configure () =  {
    bindActor(classOf[ParentActor],"PActor")
    bindActorFactory(classOf[ChildActor], classOf[ChildActor.Factory])
    bindActorFactory(classOf[ParentActor_2], classOf[ParentActor_2.Factory])
    bindActorFactory(classOf[ChildActor_2], classOf[ChildActor_2.Factory])
  }
}


object ParentActor_2 {  trait Factory { def apply() : Actor } }
class  ParentActor_2 @Inject() (cf: ChildActor_2.Factory) extends Actor with InjectedActorSupport {
  Logger.debug("ParentActor_2: created")
  val cactor = injectedChild(cf(4),"childActor_2")
  cactor ! 10

  def receive = { case _ => Logger.debug("ParentActor_2 received msg") } 
}


object ChildActor_2 { trait Factory { def apply(i: Int) : Actor } }
class  ChildActor_2 @Inject() ( i: Injector, @Assisted v: Int)  extends Actor {
  Logger.debug("ChildActor_2: created with value " + v.toString)

  def receive = { case _ => Logger.debug("ChildActor_2 received msg") } 
}


class GuiceActorProducer(val injector: Injector, val actorName: String) 
      extends IndirectActorProducer {

  override def actorClass = classOf[ParentActor_2]
  override def produce() =
    injector.getBinding(Key.get(classOf[ParentActor_2])).getProvider.get()
}

然后在我的 application.conf 中

play.modules.enabled += "package.ParentModule"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2012-07-18
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多