Как сделать доступным CustomExecutionContext для внедрения зависимостей в контроллере Play 2.6? - PullRequest
0 голосов
/ 06 ноября 2018

Я следую наряду с Воспроизведением документации Scala 2.6 и примера кода для создания неблокирующих действий , и столкнулся с некоторыми проблемами во время выполнения. Я создал новое приложение Play, используя шаблон Scala (sbt new playframework/play-scala-seed.g8).

Код, который предлагается в документации 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)
  }
}

Затем, согласно документации для использования других пулов потоков , я определил пул потоков my.executor в файле application.conf моего приложения:

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

Следует отметить, что я не хочу использовать контекст выполнения по умолчанию, поскольку я хочу подготовиться к запуску фьючерсов в отдельном контексте, который может использоваться для ограниченного ресурса, такого как пул соединений с базой данных.

Все это прекрасно компилируется с sbt compile. Однако, когда я запускаю это с sbt run и получаю доступ к своему приложению через веб-браузер, я получаю эту ошибку:

CreationException: не удалось создать инжектор, см. Следующие ошибки:

1) Нет реализации для контроллеров. MyExecutionContext был привязан. во время поиска контроллеров. MyExecutionContext для 1-го параметра контроллеров. NewController. (NewController.scala: 17) во время поиска контроллеров. NewController для 2-го параметра роутера. Маршруты. (Routes.scala: 29) в play.api.inject.RoutesProvider $ .bindingsFromConfiguration (BuiltinModule.scala: 121): Привязка (класс router.Routes to self) (через модули: com.google.inject.util.Modules $ OverrideModule -> play.api.inject.guice.GuiceableModuleConversions $$ anon $ 1)

В прошлом я использовал Play 2.3 и знаю, что внедрение зависимостей работает, когда вы определяете экземпляр объекта (через @Singleton или в модуле); однако документация Play 2.6 для DI указывает на то, что «Guice может автоматически создавать экземпляры любого класса с @Inject в его конструкторе без явной привязки его. Эта функция вызывается как раз во время привязки, описанной более подробно в документации Guice. "

У меня вопрос: какие конкретные строки кода или конфигурации мне нужно добавить в собственный образец Play, чтобы сделать это, и почему?

1 Ответ

0 голосов
/ 06 ноября 2018

Я нашел одно возможное решение при чтении далее в разделе Связывание аннотаций на странице документации Scala Dependency Injection. В частности, говорится:

Самый простой способ привязать реализацию к интерфейсу - использовать аннотацию Guice @ImplementedBy.

Итак, добавив это к my MyExecutionContext trait, вот так:

import com.google.inject.ImplementedBy

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

экземпляр MyExecutionContextImpl создается и правильно вводится в контроллер.

Слишком плохо, что эта аннотация @ImplementedBy не указана в примере кода для неблокирующего действия документация!

...