问题
I'm trying to figure out how to inject my classes with Google Guice into a play.api.Plugin. I have implemented Guice to work with my controllers and it works great.
I use:
"com.google.inject" % "guice" % "4.0-beta",
"com.tzavellas" % "sse-guice" % "0.7.1"
When a Controller instance is needed the getControllerInstance method in Global will load the appropriate implementation thanks to the injector.
Global:
object Global extends GlobalSettings {
/**
* Currently we only want to load a different module when test.
*/
private lazy val injector = {
Logger.info("Is Test: "+Play.isTest)
Play.isTest match {
case true => Guice.createInjector(new TestModule)
case false => Guice.createInjector(new CommonModule)
}
}
override def onStart(app: Application) {
Logger.info("Application has started")
}
override def onStop(app: Application) {
Logger.info("Application shutdown...")
}
override def getControllerInstance[A](clazz: Class[A]) = {
Logger.info("getControllerInstance")
injector.getInstance(clazz)
}
}
Common:
package modules
import com.tzavellas.sse.guice.ScalaModule
import services.{CallServiceImpl, CallService}
/**
* User: jakob
* Date: 11/5/13
* Time: 10:04 AM
*/
class CommonModule extends ScalaModule {
def configure() {
bind[CallService].to[CallServiceImpl]
}
}
class TestModule extends ScalaModule {
def configure() {
// Test modules!
}
}
Controller:
@Singleton
class StatsController @Inject()(callService: CallService) extends Controller with securesocial.core.SecureSocial with ProvidesHeader {
def doSomething = {
callService.call()
}
}
Now I would like to inject the same service into my Plugin, but I can't make use of the Global implementation since the plugins do not load with the getControllerInstance
class CallerPlugin (application: Application) extends Plugin {
val secondsToWait = {
import scala.concurrent.duration._
10 seconds
}
val defaultInterval = 60
val intervalKey = "csv.job.interval"
val csvParserEnabled = "csv.job.enabled"
val newDir = "csv.job.new.file.path"
val doneDir = "csv.job.done.file.path"
var cancellable: Option[Cancellable] = None
override def onStop() {
cancellable.map(_.cancel())
}
override def onStart() {
// do some cool injection of callService here!!!
import scala.concurrent.duration._
import play.api.libs.concurrent.Execution.Implicits._
val i = current.configuration.getInt(intervalKey).getOrElse(defaultInterval)
cancellable = if (current.configuration.getBoolean(csvParserEnabled).getOrElse(false)) {
Some(
Akka.system.scheduler.schedule(0 seconds, i minutes) {
callService.call()
})
} else None
}
}
I guess there should be a way of implementing the injection in the onStart method somehow and there is probably some nice easy way of doing this but I can't figure it out. Thank you!
回答1:
If I understood your question correctly, you're wondering how to instantiate and use a Guice injector. Well it's really simple:
val injector = Guice.createInjector(new CommonModule)
val callService = injector.getInstance(classOf[CallService])
And like that you have an instance of CallServiceImpl
. If you look at your Global.scala, this is exactly what you do there. I haven't used Play plugins, so I'm not sure how you instantiate them, but I think a more idiomatic way would be, instead of putting it in plugin's onStart
, to inject this CallService
as a parameter to CallerPlugin
(like you do for the controller). That way you could pass the responsibility of dependency injection down the tree, so that ideally you would end up with only one injector (probably in Global
).
回答2:
From what I found so far the best way to achieve this is to set plugin's dependency in Global.onStart()
.
public class Global extends GlobalSettings{
public Injector injector = createInjector();
private Injector createInjector(){
return Guice.createInjector(new SomeGuiceModule());
}
@Override
public void onStart(Application application) {
CallerPlugin plugin = application.plugin(CallerPlugin.class);
plugin.setCallService(injector.getInstance(CallService.class));
}
}
Make sure that plugin number is lower that 10000
. Global has 10000
, so, your plugin will be started before Global.onStart()
gets called.
来源:https://stackoverflow.com/questions/19786666/is-there-a-nice-play2-way-of-injecting-instances-in-play-plugins-with-guice