2

Play と Akka を使用して Web サービスを構築しましたが、Web サービスがクライアントである別の Web サービスを統合する必要があります。

私のデフォルトのコントローラ(関連付けられたルートファイルを含む)は次のようになります

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

これにより、大規模なアクター システムがスピンアップし、すべてがうまくいきます。

アクターの 1 つは以下のように定義されています -

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

私の問題は、このアクターから新しい Web サービスを呼び出す必要があることです。この Web サービスは、このアクターからの結果を記録するデータベースです。

私は(特に)からの指示を見て、それに従いました

  1. https://playframework.com/documentation/2.5.x/ScalaWS
  2. Play Framework 2.5 での抽象クラスとオブジェクトによる依存性注入

上記の手順に従って、アクセスする必要があるクラスに WSClient を挿入することになっています。

以下のように、2 番目のコントローラーへの依存性注入を解決できます。

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

これは機能し、ルート ファイルでマップされている URL にアクセスして「投稿」アクションを実行し、Web サービスにアクセスできます。また、現在、2つのコントローラーがあります。

私の問題は、ActorMgr (Akka アクター) から Web サービス コントローラーの "post" メソッドにアクセスすることです。どうすれば有効にできますか?

4

1 に答える 1

0

多くの調査の後、ここで調査結果を更新したいと思いました。以下のように特定の問題を解決できましたが、ここで言うべきことがたくさんあります。

最初に私の具体的な解決策 -

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 を使用し、トップレベルのアクターを注入する
  3. Playframework + Akka + Guice の使用と子アクターの注入
  4. playframework + Akka + Guice を使用しますが、トップレベルのアクターとアクター システムを「注入」するのではなく作成します。

上記のそれぞれを解決する方法を次に示します。

  1. (1) については、 guice akka のチュートリアルを参照してください。
  2. (2) & (3) については、 Playframework のドキュメントを参照してください。
  3. (4) については、これはもう少しトリッキーです

「IndirectActorProducer」を拡張し、それを使用して ActorRef を作成する必要があります。問題は、"Props" が 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"
于 2016-10-11T06:35:42.993 に答える