欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Spring IOC 容器启动流程分析

程序员文章站 2023-09-04 21:38:01
使用 spring 时,xml 和注解是使用得最多的两种配置方式,虽然是两种完全不同的配置方式,但对于 ioc 容器来说,两种方式的不同主要是在 beandefinitio...

使用 spring 时,xml 和注解是使用得最多的两种配置方式,虽然是两种完全不同的配置方式,但对于 ioc 容器来说,两种方式的不同主要是在 beandefinition 的解析上。而对于核心的容器启动流程,仍然是一致的。

abstractapplicationcontext 的 refresh 方法实现了 ioc 容器启动的主要逻辑,启动流程中的关键步骤在源码中也可以对应到独立的方法。接下来以  abstractapplicationcontext 的实现类  classpathxmlapplicationcontext 为主 ,并对比其另一个实现类 annotationconfigapplicationcontext , 解读 ioc 容器的启动过程。

abstractapplicationcontext.refresh

@override
 public void refresh() throws beansexception, illegalstateexception {
 synchronized (this.startupshutdownmonitor) {
  // prepare this context for refreshing.
  preparerefresh();

  // tell the subclass to refresh the internal bean factory.
  configurablelistablebeanfactory beanfactory = obtainfreshbeanfactory();

  // prepare the bean factory for use in this context.
  preparebeanfactory(beanfactory);

  try {
  // allows post-processing of the bean factory in context subclasses.
  postprocessbeanfactory(beanfactory);

  // invoke factory processors registered as beans in the context.
  invokebeanfactorypostprocessors(beanfactory);

  // register bean processors that intercept bean creation.
  registerbeanpostprocessors(beanfactory);

  // initialize message source for this context.
  initmessagesource();

  // initialize event multicaster for this context.
  initapplicationeventmulticaster();

  // initialize other special beans in specific context subclasses.
  onrefresh();

  // check for listener beans and register them.
  registerlisteners();

  // instantiate all remaining (non-lazy-init) singletons.
  finishbeanfactoryinitialization(beanfactory);

  // last step: publish corresponding event.
  finishrefresh();
  }

  // ...
 }
 }

applicationcontext 和 beanfactory 的关系

classpathxmlapplicationcontext 和  annotationconfigapplicationcontext 的继承树如下所示。两者都继承自  abstractapplicationcontext 。

详解Spring IOC 容器启动流程分析 

applicationcontext 继承树( 高清大图 )

详解Spring IOC 容器启动流程分析 

beanfactory 继承树( 高清大图 )

applicationcontext 是 ioc 容器的承载体,而  beanfactory 是操作这个容器的工具,两者关系紧密,相互协作。 refresh 方法实现了 applicationcontext 和 beanfactory 相互协作的主要过程,不同之处主要在子类  abstractrefreshableapplicationcontext 和 genericapplicationcontext 中实现,两者使用的 beanfactory 都为 defaultlistablebeanfactory , defaultlistablebeanfactory 的定义如下:

defaultlistablebeanfactory :

public class defaultlistablebeanfactory extends abstractautowirecapablebeanfactory
  implements configurablelistablebeanfactory, beandefinitionregistry, serializable

可见 defaultlistablebeanfactory 实现了  configurablelistablebeanfactory ,意味着是可配置,可遍历的,至于为什么可以,让我们继续往下寻找找答案。

beandefinition 的获取

defaultlistablebeanfactory 中使用 map 结构保存所有的 beandefinition 信息:

defaultlistablebeanfactory :

private final map<string, beandefinition> beandefinitionmap = new concurrenthashmap<>(256);


classpathxmlapplicationcontext 中的解析
使用 beandefinitiondocumentreader (可参看 defaultbeandefinitiondocumentreader.processbeandefinition 方法) 将 xml 中的 bean 解析为 beandefinition , 然后由 beandefinitionregistry 注册到 beanfactory 中。 入口: abstractapplicationcontext.refreshbeanfactory (在 refresh 中调用)

annotationconfigapplicationcontext 中的解析
通过 beandefinitionscanner 扫描 bean 声明,解析为 beandefinition 并由 beandefinitionregistry 注册到 beanfactory 中。 入口: annotationconfigapplicationcontext 的构造函数。

为什么 classpathxmlapplicationcontext 的入口是在 refreshbeanfactory 方法中 ?
abstractapplicationcontext.refreshbeanfactory 定义如下:

abstractapplicationcontext :

protected abstract void refreshbeanfactory() throws beansexception, illegalstateexception

可见是一个抽象方法,具体实现在子类中。只有 "refreshable" 的 beanfactory 才会在该方法中实现具体操作,如  abstractrefreshableapplicationcontext :

abstractrefreshableapplicationcontext :

@override
 protected final void refreshbeanfactory() throws beansexception {
 if (hasbeanfactory()) {
  destroybeans();
  closebeanfactory();
 }
 try {
  defaultlistablebeanfactory beanfactory = createbeanfactory();
  beanfactory.setserializationid(getid());
  customizebeanfactory(beanfactory);
  loadbeandefinitions(beanfactory);
  synchronized (this.beanfactorymonitor) {
  this.beanfactory = beanfactory;
  }
 }
 catch (ioexception ex) {
  throw new applicationcontextexception("i/o error parsing bean definition source for " + getdisplayname(), ex);
 }
 }

可见 abstractrefreshableapplicationcontext.``refreshbeanfactory 方法会检查 beanfactory 是否已经存在( hasbeanfactory ),已经存在就先销毁所有的 bean( destorybeans )并关闭( closebeanfactory ) beanfactory ,然后再创建( createbeanfactory )新的。 而  genericapplicationcontext.refreshbeanfactory 中会检查是否为第一次调用,不是就抛出异常,不执行其他逻辑,即  genericapplicationcontext 不是 "refreshable"的。

主流程分析

refresh 方法在  abstractapplicationcontext 中定义,其中的  obtainfreshbeanfactory 方法调用了 getbeanfactory 方法,该方法用于获取  beanfactory ,这里为  defaultlistablebeanfactory ,接下来无特别说明,大部分的方法和变量都将取自  abstractapplicationcontext 和   defaultlistablebeanfactory 。 

详解Spring IOC 容器启动流程分析 

高清大图

beanpostprocessor

beanpostprocessor 接口让开发者在 ioc 容器对 bean 进行实例化时收到回调( postprocessafterinitialization 和  postprocessbeforeinitialization 方法)。spring 框架内部的许多通知( aware )就是通过这个接口实现,如  applicationcontextawareprocessor ,  servletcontextawareprocessor ,他们的实现会在  postprocessbeforeinitialization 方法中进行检查,若实现了特定接口,就会调用 aware 的回调方法,给予通知:

servletcontextawareprocessor :

@override
 public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception {
 if (getservletcontext() != null && bean instanceof servletcontextaware) {
  ((servletcontextaware) bean).setservletcontext(getservletcontext());
 }
 if (getservletconfig() != null && bean instanceof servletconfigaware) {
  ((servletconfigaware) bean).setservletconfig(getservletconfig());
 }
 return bean;
 }

在 postprocessbeanfactory 方法中,子类可以通过 beanfactory.addbeanpostprocessor 方法添加自己的 beanpostprocessor 到 beanfactory 中,最终将保存到 beanfactory 的  beanpostprocessors (实为 copyonwritearraylist ) 中。 preparebeanfactory 和 registerbeanpostprocessors 方法是集中实例化并添加这些 bean 的地方。

beanfactorypostprocessor 和 beandefinitionregistrypostprocessor
从"beandefinition 的获取"的介绍可以知道 beandefinitionregistry 用于将  beandefinition 注册到 beanfactory 中, genericapplicationcontext 和  defaultlistablebeanfactory 都实现了该接口, genericapplicationcontext 中的实现直接调用了 beanfactory 的实现。

beanfactorypostprocessor 和 beandefinitionregistrypostprocessor 与  beanpostprocessor 类似,但从他们的命名就可以看出,所针对的目标不同,分别是 beanfactory 和  beandefinitionregistry: 1 beanfactorypostprocessor 回调让开发者有机会在 beanfactory 已经初始化好的情况下对 beanfactory 的一些属性进行覆盖,或是对  beandefinitionmap 中的  beandefinition 进行修改。 2 beandefinitionregistrypostprocessor 则让开发者可以继续添加  beandefinition 到 beanfactory 中。

具体逻辑在 invokebeanfactorypostprocessors 中实现,这里首先会将所有实现了 beanfactorypostprocessors 的 bean 实例化,然后调用其回调方法( postprocessbeandefinitionregistry 或  postprocessbeanfactory 方法)。

对于这部分 bean 的实例化和进行回调有一定的优先级规则。 priorityordered 继承自 ordered 接口,实现了  priorityordered 的  beandefinitionregistrypostprocessor 将最先被实例化并调用,然后同样的规则来回调实现了  beanfactorypostprocessor 的 bean: priorityordered > ordered > 未实现 ordered 的

在 registerbeanpostprocessors 方法中对 beanpostprocessor 的实例化也有这样的优先级规则: priorityordered > ordered > 未实现 ordered 的 > mergedbeandefinitionpostprocessor

applicationeventmulticaster

在 initapplicationeventmulticaster 中会对  applicationeventmulticaster 进行初始化: 首先会检查是否已经有了 applicationeventmulticaster 的  beandefinition (在  beandefinitionmap 中检查),有就让容器进行实例化,没有就使用框架默认的  applicationeventmulticaster (即 simpleapplicationeventmulticaster ),先实例化,然后注册到容器中( messagesource 在 initmessagesource 方法中也是同样的方式进行初始化)。

事件的起始发送处将事件包装为 applicationevent ,并通过  applicationeventpublisher 提交给  applicationeventmulticaster , applicationeventmulticaster 会将事件广播给  applicationlistener ,处理最终的分发。

abstractapplicationeventmulticaster 中的 applicationlisteners( 实为 linkedhashset<applicationlistener>) 变量保存了所有的广播接收者, registerlisteners 方法会将所有的  applicationlistener 添加到该集合中。

finishrefresh 方法中有一个对  contextrefreshedevent 事件的广播可以作为参考,最终事件会由  multicastevent 方法处理:

simpleapplicationeventmulticaster.multicastevent

@override
 public void multicastevent(final applicationevent event, @nullable resolvabletype eventtype) {
 resolvabletype type = (eventtype != null ? eventtype : resolvedefaulteventtype(event));
 executor executor = gettaskexecutor();
 for (applicationlistener<?> listener : getapplicationlisteners(event, type)) {
  if (executor != null) {
  executor.execute(() -> invokelistener(listener, event));
  }
  else {
  invokelistener(listener, event);
  }
 }
 }

那么在我们自己的 bean 中如何得到这个 applicationeventpublisher 呢? applicationcontext 的定义如下:

applicationcontext :

public interface applicationcontext extends environmentcapable, listablebeanfactory, hierarchicalbeanfactory,
 messagesource, applicationeventpublisher, resourcepatternresolver {

可见 applicationcontext 继承了  applicationeventpublisher ,这就说明  abstractapplicationcontext 也是一个  applicationeventpublisher 。在我们自己的 bean 中通过实现  applicationeventpublisheraware ,我们就能通过  setapplicationeventpublisher 回调得到  applicationeventpublisher 。

上面我们提到 spring 的许多 aware 是通过  beanpostprocessor 实现的, applicationeventpublisheraware 也不例外:

applicationcontextawareprocessor :

@override
 @nullable
 public object postprocessbeforeinitialization(final object bean, string beanname) throws beansexception {
 // ...
    if (bean instanceof aware) {
  if (bean instanceof environmentaware) {
  ((environmentaware) bean).setenvironment(this.applicationcontext.getenvironment());
  }
  if (bean instanceof embeddedvalueresolveraware) {
  ((embeddedvalueresolveraware) bean).setembeddedvalueresolver(this.embeddedvalueresolver);
  }
  if (bean instanceof resourceloaderaware) {
  ((resourceloaderaware) bean).setresourceloader(this.applicationcontext);
  }
  if (bean instanceof applicationeventpublisheraware) {
  ((applicationeventpublisheraware) bean).setapplicationeventpublisher(this.applicationcontext);
  }
  if (bean instanceof messagesourceaware) {
  ((messagesourceaware) bean).setmessagesource(this.applicationcontext);
  }
  if (bean instanceof applicationcontextaware) {
  ((applicationcontextaware) bean).setapplicationcontext(this.applicationcontext);
  }
 }
    // ...
 }

ioc 容器在实例化我们的 bean 时会调用 applicationcontextawareprocessor . postprocessbeforeinitialization 方法,该方法会检查我们的 bean,我们的 bean 如果实现了  applicationeventpublisheraware ,那么就会回调  setapplicationeventpublisher 方法将  applicationcontext (即 applicationeventpublisher ) 传给我们,我们就能够发布事件。

beanfactory.getbean

beanfactory 的几个重载了的 getbean 方法是 bean 最终进行实例化的地方, registerbeanpostprocessors ,  invokebeanfactorypostprocessors 和  finishbeanfactoryinitialization 方法都调用了 getbean 方法对一些特定 bean 进行了实例化。

finishbeanfactoryinitialization 中通过调用 beanfactory 的  preinstantiatesingletons 对单例 bean 进行实例化。 beanfactory 和  beandefinition 都具有父子的概念,在子级找不到指定的 bean 时将一直往上(父级)找,找到就进行实例化

总结

spring ioc 容器的启动步骤可总结如下: 1 初始化 applicationcontext 环境属性的初始化和验证,启动时间记录和相关标记设置,应用事件和监听者的初始化。

2 准备好容器中的 beandefinition (eager-initializing beans) 对 beandefinition 的解析、扫描和注册, beandefinition 的扫描和注册大致可以分为 xml 和注解两种,两种方式各自使用的组件有所不同,该步骤的时间也可以在最前面。

3 初始化 beanfactory 准备好 beanfactory 以供 applicationcontext 进行使用,对接下来将要使用到的 bean 进行实例化,资源进行准备,属性进行设置。

4 注册 beanpostprocessors beanpostprocessors 是进行扩展的关键组件,需要在该步骤中进行注册,可分为两种类型: 一种是框架使用者提供的,用于特定业务功能的,另一种是框架开发者提供的,用于扩展框架功能。

5 调用 beandefinitionregistrypostprocessor beandefinitionregistrypostprocessor 是一种功能增强,可以在这个步骤添加新的  beandefinition 到 beanfactory 中。

6 调用 beanfactorypostprocessor beanfactorypostprocessor 是一种功能增强,可以在这个步骤对已经完成初始化的 beanfactory 进行属性覆盖,或是修改已经注册到 beanfactory 的  beandefinition 。

7 初始化 messagesource 和  applicationeventmulticaster messagesource 用于处理国际化资源, applicationeventmulticaster 是应用事件广播器,用于分发应用事件给监听者。

8 初始化其他 bean 和进行其他的的上下文初始化 主要用于扩展

9 注册 applicationlistene 将  applicationlistene 注册到 beanfactory 中,以便后续的事件分发

10 实例化剩余的 bean 单例 步骤 4 到 9 都对一些特殊的 bean 进行了实例化,这里需要对所有剩余的单例 bean 进行实例化

11 启动完成 资源回收,分发"刷新完成"事件。

总结

以上所述是小编给大家介绍的spring ioc 容器启动流程分析,希望对大家有所帮助