简体   繁体   中英

Play Framework 2.5.x: Inject Environment in a Module

Play app contains a custom module that initializes DB/Tables during the app start. Starting with v2.5.x, the application mode(prod, test, dev) needs to be injected rather than using Current. I tried to apply the following inject parameters in the module code but saw compile errors.

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()
  }
}

Is there a prescribed way of looking up Environment/Mode during module initialization in Play 2.5.x (Scala)?

I will rewrite your code to remove a small possible confusion here. This is exactly your code with a small rename of the type parameters:

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()
  }
}

I renamed the type parameters to avoid confusion with play.api.Environment . I have the felling that this is not what you want, since MyInitClass does not actively receive an play.api.Environment anywhere.

If you want to do some initialization, why not go with something more simple and direct like this:

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
    }
  }
}

Edit:

A more idiomatic and recommended way to replace GlobalSettings.onStart is 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 .

So, we can rewrite your code to be something like this:

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()
  }
}

Notice how I've removed the trait since it is not adding any value here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM