com.google.inject.AbstractModule
本类实现 com.google.inject.Module接口
Guice 用来配置依赖关系
play.api.inject.Module
抽象类,源码注释很直观
/**
* A Play dependency injection module.
* Play 依赖项注入模块。
*
* Dependency injection modules can be used by Play plugins to provide bindings for JSR-330 compliant
* ApplicationLoaders. Any plugin that wants to provide components that a Play application can use may implement
* one of these.
*
* Providing custom modules can be done by appending their fully qualified class names to `play.modules.enabled` in
* `application.conf`, for example
*
* {{{
* play.modules.enabled += "com.example.FooModule"
* play.modules.enabled += "com.example.BarModule"
* }}}
*
* It is strongly advised that in addition to providing a module for JSR-330 DI, that plugins also provide a Scala
* trait that constructs the modules manually. This allows for use of the module without needing a runtime dependency
* injection provider.
*
* The `bind` methods are provided only as a DSL for specifying bindings. For example:
*
* {{{
* def bindings(env: Environment, conf: Configuration) = Seq(
* bind[Foo].to[FooImpl],
* bind[Bar].to(new Bar()),
* bind[Foo].qualifiedWith[SomeQualifier].to[OtherFoo]
* )
* }}}
*/
bindings 方法
获取该模块的其他依赖
在 GuiceApplicationBuilder 构造参数中被调用 GuiceableModule extends GuiceableModuleConversions
在 特质 GuiceableModuleConversions 中调用
bindings 是在模块继承 play.api.inject.Module 后需要实现的方法
返回的是列表,就是 bind 方法创建的每一个对象
bind 方法
通过key创建对象
Modules 类
作用:从环境中找到模块,并装载
// 默认加载的用户定义的模块
private val DefaultModuleName = "Module"
locate 加载配置文件信息
val includes = configuration.getOptional[Seq[String]]("play.modules.enabled").getOrElse(Seq.empty)
val excludes = configuration.getOptional[Seq[String]]("play.modules.disabled").getOrElse(Seq.empty)
返回 Seq[GuiceableModule]
GuiceableModule,包含了 AbstractModule
trait GuiceableModule {
def guiced(env: Environment, conf: Configuration, binderOptions: Set[BinderOption]): Seq[GuiceModule]
def disable(classes: Seq[Class[_]]): GuiceableModule
}
这两个代码开始有点疑惑了,其实最终用的还是上面的特质,下面的只不过是它的工具类而已,不知道我这样理解是否对。😂
/**
* Loading and converting Guice modules.
*/
object GuiceableModule extends GuiceableModuleConversions {
def loadModules(environment: Environment, configuration: Configuration): Seq[GuiceableModule] = {
Modules.locate(environment, configuration).map(guiceable)
}
GuiceBuilder
抽象类,用于创建支持Guice的 Play inject 的构建器。
createModule
返回 com.google.inject.Module,看val injectorModule = GuiceableModule.guice
/**
* Creation of the Guice Module used by the injector.
* Libraries like Guiceberry and Jukito that want to handle injector creation may find this helpful.
*/
def createModule(): GuiceModule = {
import scala.collection.JavaConverters._
// 调用 guice
val injectorModule = GuiceableModule.guice(
Seq(
bind[GuiceInjector].toSelf,
bind[GuiceClassLoader].to(new GuiceClassLoader(environment.classLoader)),
bind[PlayInjector].toProvider[GuiceInjectorWithClassLoaderProvider],
// Java API injector is bound here so that it's available in both
// the default application loader and the Java Guice builders
bind[play.inject.Injector].to[play.inject.DelegateInjector]
),
binderOptions
)
val enabledModules = modules.map(_.disable(disabled))
val bindingModules = GuiceableModule.guiced(environment, configuration, binderOptions)(enabledModules) :+ injectorModule
val overrideModules = GuiceableModule.guiced(environment, configuration, binderOptions)(overrides)
GuiceModules.`override`(bindingModules.asJava).`with`(overrideModules.asJava)
}
guice方法
lock ! new com.google.inject.AbstractModule
/**
* Convert the given Play bindings to a Guice module.
*/
def guice(bindings: Seq[PlayBinding[_]], binderOptions: Set[BinderOption]): GuiceModule = {
// 看这里,play给你构建了AbstractModule,这些是play框架默认Module的实现方式
new com.google.inject.AbstractModule {
override def configure(): Unit = {
binderOptions.foreach(_(binder))
for (b <- bindings) {
val binding = b.asInstanceOf[PlayBinding[Any]]
val builder = binder().withSource(binding).bind(GuiceKey(binding.key))
binding.target.foreach {
case ProviderTarget(provider) => builder.toProvider(GuiceProviders.guicify(provider))
case ProviderConstructionTarget(provider) => builder.toProvider(provider)
case ConstructionTarget(implementation) => builder.to(implementation)
case BindingKeyTarget(key) => builder.to(GuiceKey(key))
}
(binding.scope, binding.eager) match {
case (Some(scope), false) => builder.in(scope)
case (None, true) => builder.asEagerSingleton()
case (Some(scope), true) =>
throw new GuiceLoadException("A binding must either declare a scope or be eager: " + binding)
case _ => // do nothing
}
}
}
}
}
}
看着看着就看到Play的启动流程去了,稍微整理了一下,调试跟踪最开始的入口是从Mailbox
开始的,前面先忽略,直接从newApplication开始。
感觉还是有点晕 😵,有时间在继续分析…