【问题标题】:Create an Instance of class which does DI via Playframework Guice Independently in Scala在 Scala 中创建一个通过 Playframework Guice 独立执行 DI 的类实例
【发布时间】:2016-07-20 02:53:27
【问题描述】:

我正在使用 play-slick 和与之相关的程序(例如批处理)开发 Playframework2.5。

目前的项目结构是这样的

/rootPlayProject
  /app
    /controllers
    /filters
    /services
    ...
  Modules
  /core (sub-project - DAOs,services are placed here)
  /batch (sub-project depends on core)

我几乎在所有地方都使用 Guice DI,包括数据库访问对象 (DAO)。 核心中的接口绑定在Module 中的core 中,最终被根项目中的Module 继承。

核心模块(/rootPlayProject/core/CoreModule.scala)

class CoreModule extends AbstractModule {
  override def configure() = {
    bind(classOf[FooDAO]).to(classOf[FooDAOImpl])
    ....
  }
}

根模块(/rootPlayProject/Modules.scala)

class Module extends CoreModule {
  override def configure() = {
    super.configure()
    bind(classOf[FooService]).to(classOf[FooServiceImpl])
  }
}

虽然这作为 Playframework 应用程序非常有效,但我想将核心模块用于批处理程序,并且我想在没有 playframework 的情况下运行批处理。

到目前为止,我尝试过这样的事情

object BatchA {
  def main(args: Array[String]) = {
    val injector = Guice.createInjector(new CoreModule)
    val foo = injector.getInstance(classOf[FooDAO])
    //do something with foo.
  }
}

但由于我的 DAO 需要 Playframework 创建的东西,例如 ExecutionContextplay.api.db.slick.DatabaseConfigProvider@play.db.NamedDatabase,因此上面的代码无法运行。

我的问题是,如果没有 play 应用程序构建器,我怎样才能让这些东西绑定?

提前致谢。

【问题讨论】:

    标签: scala playframework guice


    【解决方案1】:

    答案取决于您是否真的想将 Play Framework 与您的 DAO 分离。

    选项 1:不要解耦

    您的主要方法可以简单地在您的 val injector 行之前添加以下行:

    val application = new GuiceApplicationBuilder()
      .in(Environment(new File("."), this.getClass.getClassLoader, Mode.Prod))
      .build
    Play.start(application)
    

    选项 2:解耦

    或者,您可以提供可以提供特定于环境的ExecutionContext 的可注入类。如果要注入DatabaseConfigProvider,则必须执行进一步的抽象以消除对 Play 的直接依赖。注释将遵循抽象的 Play 特定实现。


    在我自己的项目中遇到这种情况时,我选择了选项 1,因为对 Play 的依赖对我的影响还不够严重。

    【讨论】:

    • Option1 的情况意味着播放应用程序正在运行,而我正在做我想做的事,对吧?如果不是太难,我更喜欢后者,这样我就不必运行播放应用程序来执行批处理。
    • 在你的情况下,选项 2 可能更合理。
    【解决方案2】:

    GuiceInjectorBuilder 做到这一点。

    trait PlayInjector {
      lazy val injector = new GuiceInjectorBuilder().configure(Configuration.load(Environment.simple(mode = Mode.Dev)))
      .bindings(new BuiltinModule, new CoreModule, new SlickModule).disable(classOf[Application]).injector
    
      def closeInjector = injector.instanceOf[DefaultApplicationLifecycle].stop
    }
    

    BuiltinModule 绑定 Play 基本模块,例如 ExecutionContextExecutionContextExecutorActorSystem。 您可以制作自己的模块来只绑定您需要的东西,使用BuiltinModule 并禁用您不需要的类更简单。

    如何使用它

    object Foo extends PlayInjector {
      def main(args: Array[String]) = {
        val foo = injector.instanceOf[FooDAO]
        val bar = injector.instanceOf[BarDAO]
        //do something
        //when you finish things you want to do
        closeInjector
      }
    }
    

    由于 PlaySlick 等一些模块使用ApplicationLifecycle.addStopHook 来处理关闭操作。执行它们比调用sys.exit()

    更安全

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 2012-03-31
      • 2012-03-27
      • 2021-04-07
      • 2015-09-09
      相关资源
      最近更新 更多