2016-10-02 81 views
2

我已經使用Play & Akka構建了一個Web服務,現在需要集成另一個Web服務,其中我的Web服務是客戶端。與Akka Actor和播放框架一起使用WebService

我的默認控制器(帶相關的路由文件)看起來像

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

這旋轉了一個大演員系統,一切都很好。

一個演員的定義如下 -

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. 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」方法。我如何啓用該功能?

+0

可以使用依賴注入創造者,在這裏看到:https://www.playframework.com/documentation/2.5.x/ScalaAkka#依賴注入演員 – Haspemulator

+0

Haspemulator,感謝您的迴應。它回答了我原來的問題的一部分(我如何依賴注入演員),但沒有解決我的問題。我重新回顧了我的問題的部分內容,以便更清楚。 –

+0

這是最後做的, –

回答

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. 使用阿卡& Guice和不使用Playframework
  2. 使用Playframework +阿卡+ Guice和注射頂級演員
  3. 使用Playframework + Akka + Guice和注射兒童演員
  4. 使用playframework + Akka + Guice但創建不「injectin g「你的頂級演員&演員系統。

這裏是你將如何解決上述每一個。

  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"