GuiceApplicationLoader configuration error

2020-05-01 09:57发布

问题:

So, I'm trying to implement compile time DI with something that looks like this:

package modules

class MyModule extends AbstractModule {
  def configure() {
    bind(classOf[MyT]).to(classOf[MyTImpl])
  }
}

class MyApplicationLoader extends GuiceApplicationLoader {
  override protected def builder(context: ApplicationLoader.Context): GuiceApplicationBuilder = {
  initialBuilder
    .in(context.environment)
    .loadConfig(context.initialConfiguration)
    .overrides(overrides(context): _*)
    .load(new MyModule)
  }
}

application.conf includes a line:

play.application.loader = "modules.MyApplicationLoader"

However, when I try to spin up the application, I get an error:

ConfigurationException: Guice configuration errors:

1) No implementation for play.api.Application was bound.
  while locating play.api.Application

1 error

No source available, here is the exception stack trace:
->com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for play.api.Application was bound.
  while locating play.api.Application

1 error
     com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1042)
     com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1001)
     com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
....

Don't understand why this isn't working, as none of the examples I've seen for this do anything more involved. What am I overlooking?

回答1:

Use bindings instead of load:

class MyApplicationLoader extends GuiceApplicationLoader {
  override protected def builder(context: ApplicationLoader.Context): GuiceApplicationBuilder = {
  initialBuilder
    .in(context.environment)
    .loadConfig(context.initialConfiguration)
    .overrides(overrides(context): _*)
    .bindings(new MyModule)
  }
}


回答2:

I'm not sure what you are trying to achieve here, but that's not how compile time dependency injection works. Guice does its magic at runtime. However, if you want to have your dependencies ready as soon as the application starts, use eager loading. Guice already provides all the tools needed:

MyModule

class MyModule extends AbstractModule {
  def configure() {
    bind(classOf[MyT]).to(classOf[MyTImpl]).asEagerSingleton()
  }
}

application.conf

play.modules.enabled += "modules.MyModule"

Because MyTImpl will be loaded as a singleton, it must have no instance bound data. Think of an object in scala terms. Always the exact same instance of MyTImpl will be injected.