4

我试图弄清楚如何将我的 Google Guice 类注入到 play.api.Plugin 中。我已经实现了 Guice 来与我的控制器一起工作,并且效果很好。

我用:

"com.google.inject" % "guice" % "4.0-beta",
"com.tzavellas" % "sse-guice" % "0.7.1"

当需要控制器实例时,Global 中的 getControllerInstance 方法将加载适当的实现,这要归功于注入器。

全球的:

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

常见的:

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

控制器:

@Singleton
class StatsController @Inject()(callService: CallService) extends Controller with securesocial.core.SecureSocial with ProvidesHeader  {

    def doSomething = {
        callService.call()
    }   
}

现在我想将相同的服务注入到我的插件中,但我无法使用 Global 实现,因为插件不使用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
  }
}

我想应该有一种方法可以在 onStart 方法中以某种方式实现注入,并且可能有一些很好的简单方法可以做到这一点,但我无法弄清楚。谢谢!

4

2 回答 2

0

到目前为止,我发现实现这一目标的最佳方法是将插件的依赖项设置为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));
    }
}

确保插件编号低于10000. Global has 10000,因此,您的插件将在Global.onStart()被调用之前启动。

于 2014-12-03T11:49:19.230 回答
0

如果我正确理解了您的问题,您想知道如何实例化和使用 Guice 注入器。嗯,这真的很简单:

val injector = Guice.createInjector(new CommonModule)
val callService = injector.getInstance(classOf[CallService])

就像这样,你有一个CallServiceImpl. 如果您查看您的 Global.scala,这正是您在那里所做的。我没有使用过 Play 插件,所以我不确定你是如何实例化它们的,但我认为一种更惯用的方式是,而不是将其放入 plugin's中,将其作为参数onStart注入(就像你为控制器所做的那样)。这样,您可以将依赖注入的责任向下传递到树中,因此理想情况下您最终将只有一个注入器(可能在.CallServiceCallerPluginGlobal

于 2013-11-13T13:49:45.833 回答