playframework Module加载流程

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开始。
在这里插入图片描述

感觉还是有点晕 😵,有时间在继续分析…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值