Play Framework 2.5.x:在模块中注入环境

Play Framework 2.5.x: Inject Environment in a Module

Play 应用程序包含一个自定义模块,可在应用程序启动期间初始化 DB/Tables。 从v2.5.x开始,需要注入application mode(prod, test, dev) 而不是使用Current。我尝试在模块代码中应用以下注入参数,但看到了编译错误。

trait MyInit[Environment] {
  val env: Environment
}

class MyInitClass[Environment] @Inject() (
  val env: Environment
) extends MyInit[Environment] {
  initializeDB()

  def initializeDB() = {
    Logger.info("MyINIT: Creating database...")
    MyDBService.createDatabase()
    Logger.info("MyINIT: Creating tables...")
    MyDBService.createTables()
  }
}

class MyModule(environment: Environment,
             configuration: Configuration) extends AbstractModule with ScalaModule {
  def configure() = {
    bind[MyInit[Environment]].to[MyInitClass[Environment]].asEagerSingleton()
  }
}

在 Play 2.5.x (Scala) 的模块初始化期间是否有规定的查找 Environment/Mode 的方法?

我将重写您的代码以消除此处可能出现的小混乱。这正是您的代码,对类型参数进行了小的重命名:

import javax.inject.Inject
import play.api.Logger
import play.api.Environment
import play.api.Configuration
import com.google.inject.AbstractModule

trait MyInit[T] {
  val env: T
}

class MyInitClass[T] @Inject() (val env: T) extends MyInit[T] {
  initializeDB()

  def initializeDB() = {
    Logger.info("MyINIT: Creating database...")
    MyDBService.createDatabase()
    Logger.info("MyINIT: Creating tables...")
    MyDBService.createTables()
  }
}

我重命名了类型参数以避免与 play.api.Environment 混淆。我觉得这不是你想要的,因为 MyInitClass 不会在任何地方主动接收 play.api.Environment

如果你想做一些初始化,为什么不像这样更简单直接:

import com.google.inject.AbstractModule
import play.api.{Configuration, Environment, Mode}

class DatabaseInitializerModule(
  environment: Environment,
  configuration: Configuration
) extends AbstractModule {

  def configure() = {
    environment.mode match {
      case Mode.Dev =>
        // Start dev database
      case Mode.Test =>
        // Start test database
      case Mode.Prod =>
        // Start prod database
    }
  }
}

编辑:

替换GlobalSettings.onStart的更惯用和推荐的方法是described at the docs

GlobalSettings.beforeStart and GlobalSettings.onStart: Anything that needs to happen on start up should now be happening in the constructor of a dependency injected class. A class will perform its initialisation when the dependency injection framework loads it. If you need eager initialisation (because you need to execute some code before the application is actually started), define an eager binding.

所以,我们可以将您的代码改写成这样:

import javax.inject.Inject

import play.api.{Environment, Mode}
import com.google.inject.AbstractModule

class DatabaseInitializer @Inject()(environment: Environment) {
  environment.mode match {
    case Mode.Dev =>
    // Start dev database
    case Mode.Test =>
    // Start test database
    case Mode.Prod =>
    // Start prod database
  }
}

class DatabaseInitializerModule extends AbstractModule {
  override def configure() = {
    bind(classOf[DatabaseInitializer]).asEagerSingleton()
  }
}

请注意我是如何删除 trait 的,因为它不会在此处添加任何值。