将WebService与Akka Actors和play框架一起使用 [英] Using a WebService with Akka Actors and the play framework

查看:97
本文介绍了将WebService与Akka Actors和play框架一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have built a web service using Play & Akka and now need to integrate another Webservice, where my web service is a client.

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

My default controller (with an associated routes file) looks like

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

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

This spins up a large actor system and everything is good.

其中一个参与者定义如下-

One of the actors is defined as below -

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

我的问题是我现在需要从此参与者调用新的Web服务.该Web服务是一个数据库,它将记录该参与者的结果.

My problem is that I now need to call a new web service from this actor. This web service is a database that will log the results from this actor.

我已经看到并遵循了其他人的指示

I have seen and followed instructions from (among others)

  1. https://playframework.com/documentation/2.5.x/ScalaWS
  2. 依赖性在Play Framework 2.5中注入抽象类和对象
  1. https://playframework.com/documentation/2.5.x/ScalaWS
  2. Dependency injection with abstract class and object in Play Framework 2.5

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

As per the instructions above, i am supposed to inject WSClient into a class where i need to access it.

我能够解决将依赖项注入第二个控制器的问题,如下所示

I am able to solve the dependency injection into a second controller as below

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

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

This works, and i can execute the "post" action, by accessing the URL that it is mapped to in the routes file, and therefore access the web service. I also now have two controllers.

我的问题是从ActorMgr(Akka Actor)访问Web服务控制器的"post"方法.如何启用该功能?

My problem is to access the web service controller "post" method from ActorMgr (an Akka Actor). How do i enable that ?

推荐答案

经过大量研究,我想在这里更新我的发现.尽管我可以解决以下特定问题,但这里还有很多要说的.

After a lot of research, i wanted to update my findings here. Though i was able to solve my specific problem as below, there is a lot more to be said here.

我的具体解决方案优先-

My specific solution first -

代替DbController,我将服务包装如下,并在需要时将其注入-

Instead of DbController, I wraped my service as below and injected it where required -

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")     
    }
}

话虽这么说,注射东西给我带来了很多问题.我终于意识到这里有一些不同的用例-

Having said that, injecting stuff gave me a ton of problems. I finally realized that there are a few distinct use cases here -

  1. 使用Akka&猜猜不使用Playframework
  2. 使用Playframework + Akka + Guice并注入顶级演员
  3. 使用Playframework + Akka + Guice并注入儿童演员
  4. 使用播放框架+ Akka + Guice BUT创建的不是注入"您的顶级演员&演员系统.
  1. Using Akka & Guice and not using the Playframework
  2. Using the Playframework + Akka + Guice and injecting a top level actor
  3. Using the Playframework + Akka + Guice and injecting child actors
  4. Using the playframework + Akka + Guice BUT creating not "injecting" your top level actor & Actor System.

这是解决上述每个问题的方法.

Here is how you would solve each of the above.

  1. 对于(1),请参阅 guice akka教程
  2. 对于(2)& (3)-请参阅 Playframework文档
  3. 对于(4),这有点棘手
  1. For (1) - Refer to guice akka tutorial
  2. For (2) & (3) - Refer to Playframework Documentation
  3. For (4) This is a little more tricky

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

You will need to extend "IndirectActorProducer" and then use that for creating your ActorRef. The problem is "Props" does not know how to interface with Guice. This is also part of the solution in (1)

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

The below sample code shows all 4 use cases, and compiles. In the code below

ParentActor-引用上述用例(2),ChildActor引用用例(3),ParentActor_2& ChildActor_2以使用案例(4).

ParentActor - Refers to use case (2) above, ChildActor to use case (3), and ParentActor_2 & ChildActor_2 to use case (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中

And then in my application.conf

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

这篇关于将WebService与Akka Actors和play框架一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆