创建一个 class 的实例,它在 Scala 中通过 Playframework Guice 独立进行 DI
Create an Instance of class which does DI via Playframework Guice Independently in Scala
我正在开发 Playframework2.5,其中包含 play-slick 和与之相关的程序,例如批处理。
当前项目结构如下
/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 创建的东西,例如 ExecutionContext
、play.api.db.slick.DatabaseConfigProvider
和 @play.db.NamedDatabase
,上面的代码没有 运行。
我的问题是,如果没有 play application builder,我如何让这些东西绑定?
提前致谢。
答案取决于您是否真的想将 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 的依赖性对我的影响还不够严重。
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 基本模块,例如 ExecutionContext
、ExecutionContextExecutor
或 ActorSystem
。
你可以让你自己的模块只绑定你需要的东西,使用 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()
更安全
我正在开发 Playframework2.5,其中包含 play-slick 和与之相关的程序,例如批处理。
当前项目结构如下
/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 创建的东西,例如 ExecutionContext
、play.api.db.slick.DatabaseConfigProvider
和 @play.db.NamedDatabase
,上面的代码没有 运行。
我的问题是,如果没有 play application builder,我如何让这些东西绑定?
提前致谢。
答案取决于您是否真的想将 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 的依赖性对我的影响还不够严重。
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 基本模块,例如 ExecutionContext
、ExecutionContextExecutor
或 ActorSystem
。
你可以让你自己的模块只绑定你需要的东西,使用 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()