【问题标题】:Scala PLAY Guice Injection and ImplicitsScala PLAY Guice 注入和隐式
【发布时间】:2018-03-20 23:49:50
【问题描述】:

我是 Scala 世界的新手,我正在使用 PLAY 来制作 API。它进展顺利,但我在理解一些符号时遇到了一些麻烦,并且没有很多关于它的文档。具体来说,我对 PLAY 网站上的一个示例中的以下控制器方法感到困惑:

class HomeController @Inject()(@Named("userParentActor") userParentActor: ActorRef,
                               cc: ControllerComponents)
                              (implicit ec: ExecutionContext) {
}

我的问题是这个构造函数发生了什么?哪一部分是构造函数,哪一部分是注入参数? ExecutionContext 是否也注入了?为什么ec 在单独的括号中?

感谢您的澄清。

【问题讨论】:

    标签: scala playframework guice


    【解决方案1】:

    只是一个有两个参数列表的构造函数,第二个列表中的参数是隐式的。

    class HomeController @Inject()(                        // list-1 start
      @Named("userParentActor") userParentActor: ActorRef, // list-1, arg-1
      cc: ControllerComponents                             // list-1, arg-2
    )(                                                     // 1 end, 2 start
      implicit ec: ExecutionContext                        // list-2, arg-1
    ) {                                                    // list-2 end
                                                           // body
    }
    

    @Inject 注释适用于两个参数列表,因此ec 也由 guice 注入(使用 Play's default thread pool)。

    @Named 注释只影响第一个参数。

    ec 参数位于单独的列表中,因为隐式参数必须在单独的列表中声明。

    它被声明在一个单独的列表中可能是因为作者预料到了控制器被手动实例化而不是依赖注入容器的用例:它更简单,因为您不必在任何地方指定默认线程池。

    【讨论】:

    • 谢谢你说得通!
    【解决方案2】:

    好的,让我们回过头来谈谈为什么 Play 会演变成这样。通常,当您想以命令式的方式编写类/方法/函数时,我们会编写如下内容:

    class XProviderFromCloud {
        def getX (xId: String) : X = ??? // ???: To be implemented
    }
    

    假设上面的代码在你models的某个地方,这样就ok了,你可以导入模型,使用这里的方法。不过好的工程 这里的方法是创建接口并测试事物:类似于测试驱动开发 (TDD)。那么在这种情况下,代码将是:

    trait XProvider{
        def getX(xId: String): x 
    }
    
    class XProviderFromCloud extends Xprovider{
        override def getX (xId: String) : X = ??? // ???: To be implemented
    }
    

    这里你通过接口,所以你可以将接口注入控制器:

    class MyController @inject()(xProvider: XProvider)
    

    所以您可以在这里看到您的控制器类,并且有许多可注入组件可供使用。我这样做的主要原因之一, 是因为我可以模拟界面并重新运行结果;并对此进行测试。所以这意味着,我不需要里面有代码 override def getX 测试实现此功能的控制器。在我确定控制器可以使用 getX 的结果后,我编写 测试getX,然后为它的主体编写代码。

    现在让我们进入下一点,使用@Named 注释。有时一个接口有多个实现(扩展了 classes),我们使用@Named注解来明确表达我们想要的实现。例如我可以扩展上面的接口 有两个类从亚马逊云(例如 S3)获取 X,另一个从谷歌云获取。就这么简单,你可以 另请查看文档:https://www.playframework.com/documentation/2.6.x/ScalaDependencyInjection#Programmatic-bindings

    ec: ExecutionContext 部分呢,您可能会问。好吧,这是稍后你想要处理并发和期货的时候。以上 代码,如果我们要调用云服务或数据库,从某种意义上说它不是并发的不好;我们需要写一个非阻塞的 并发代码,使用 Future。期货在 cpu theads 上运行,我们可以使用默认执行上下文(如您在代码中所示), 或者创建我们自己的执行上下文,如 Play 的文档所示:https://www.playframework.com/documentation/2.6.x/ScalaAsync#Creating-non-blocking-actions

    【讨论】:

      猜你喜欢
      • 2019-08-16
      • 1970-01-01
      • 2016-09-04
      • 1970-01-01
      • 1970-01-01
      • 2015-12-06
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多