2016-10-02 44 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"