如何在 Play 2.6 控制器中使“CustomExecutionContext”可用于依赖注入?

Posted

技术标签:

【中文标题】如何在 Play 2.6 控制器中使“CustomExecutionContext”可用于依赖注入?【英文标题】:How do make a `CustomExecutionContext` available for dependency injection in a Play 2.6 controller? 【发布时间】:2018-11-05 21:38:52 【问题描述】:

我正在关注Play 2.6's Scala documentation and sample code for creating non-blocking actions,但遇到了一些运行时问题。我使用Scala template (sbt new playframework/play-scala-seed.g8) 创建了一个新的 Play 应用程序。

Play 文档建议应该在新控制器中工作的代码是(此代码逐字取自 Play 文档页面,还有一些来自我的额外导入):

// some imports added by me to get the code to compile
import javax.inject.Inject
import scala.concurrent.ExecutionContext
import scala.concurrent.Future

import akka.actor.ActorSystem
import play.api.libs.concurrent.CustomExecutionContext
import play.api.mvc._
import play.api.mvc.ControllerComponents
// end imports added by me

import play.api.libs.concurrent.CustomExecutionContext

trait MyExecutionContext extends ExecutionContext

class MyExecutionContextImpl @Inject()(system: ActorSystem)
  extends CustomExecutionContext(system, "my.executor") with MyExecutionContext

class HomeController @Inject()(myExecutionContext: MyExecutionContext, val controllerComponents: ControllerComponents) extends BaseController 
  def index = Action.async 
    Future 
      // Call some blocking API
      Ok("result of blocking call")
    (myExecutionContext)
  

然后,根据documentation for using other thread pools,我在我的应用程序的application.conf文件中定义了my.executor线程池:

my.executor 
  fork-join-executor 
    parallelism-factor = 20.0
    parallelism-max = 200
  

我应该注意,我确实想要使用默认的执行上下文,因为我想准备在单独的上下文中运行未来,该上下文可能用于数据库连接池等有限资源。

所有这些都可以使用sbt compile 编译得很好。但是,当我使用 sbt run 运行此程序并在网络浏览器中访问我的应用程序时,我收到此错误:

CreationException: 无法创建注入器,看到如下错误:

1) 没有绑定 controllers.MyExecutionContext 的实现。 在定位 controllers.MyExecutionContext 对于 controllers.NewController.(NewController.scala:17) 的第一个参数 在定位控制器时。NewController 对于 router.Routes.(Routes.scala:29) 的第二个参数 在 play.api.inject.RoutesProvider$.bindingsFromConfiguration(BuiltinModule.scala:121): 绑定(class router.Routes to self)(通过模块:com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

我过去使用过 Play 2.3,并且知道当您定义对象的实例(通过 @Singleton 或在模块中)时,依赖注入会起作用;但是,Play 2.6's documentation on DI 表示“Guice 能够在其构造函数上使用 @Inject 自动实例化任何类,而无需显式绑定它。此功能被称为即时绑定,在 Guice 文档中有更详细的描述。”

我的问题是:我需要向 Play 自己的示例添加哪些特定的代码行或配置才能使其正常工作,为什么?

【问题讨论】:

在你的项目中应该有一个Modules文件可以让你绑定特定的实现。 【参考方案1】:

在进一步阅读 Scala 依赖注入文档页面的 Binding Annotations 部分时,我发现了一种可能的解决方案。它特别指出:

将实现绑定到接口的最简单方法是使用 Guice @ImplementedBy 注解。

所以,通过将其添加到我的MyExecutionContext trait,就像这样:

import com.google.inject.ImplementedBy

@ImplementedBy(classOf[MyExecutionContextImpl])
trait MyExecutionContext extends ExecutionContext

MyExecutionContextImpl 的一个实例被实例化并正确注入到控制器中。

太糟糕了,@ImplementedBy 注释没有在non-blocking action 文档的示例代码中列出!

【讨论】:

以上是关于如何在 Play 2.6 控制器中使“CustomExecutionContext”可用于依赖注入?的主要内容,如果未能解决你的问题,请参考以下文章

为 play framework 2.6 配置的默认控制器包在哪里?

在 Play 框架 Java 2.6 中添加 Paypal 按钮

在 Play 2.6 上使用 stb-native-packager 和 Debian 和 SystemV

将 Play 框架中的 WebSockets 从 2.4 版转换为 2.6 版

在Play 2.6的conf文件中Hikari,Quill和Postgres之间的冲突

如何在控制器方法中使 JWT 令牌授权可选