深入理解Spring容器初始化(三):事件及其他配置的初始化

前言

我们知道,spring 的启动其实就是容器的启动,而一般情况下,容器指的其实就是上下文 ApplicationContext

AbstractApplicationContext 作为整个 ApplicationContext 体系中最高级的抽象类,为除了 ComplexWebApplicationContextSimpleWebApplicationContext 这两个容器外的全部容器,规定好了 refresh 的整体流程,所有的容器在完成一些自己的初始化配置后,都需要调用该 refresh 方法,依次完成指定内容的初始化。

也就是说,读懂了 AbstractApplicationContext.refresh() 方法,其实就读懂了容器的启动流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {

// ================= 一、上下文的初始化 =================
// 准备上下文
prepareRefresh();
// 通知子类刷新内部工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂以便在当前上下文中使用
prepareBeanFactory(beanFactory);

try {
// ================= 二、BeanFactory的初始化 =================
// 对工厂进行默认后置处理
postProcessBeanFactory(beanFactory);
// 使用后置处理器对工厂进行处理
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean后置处理器
registerBeanPostProcessors(beanFactory);

// ================= 三、事件,Bean及其他配置的初始化 =================
// 初始化此上下文的消息源
initMessageSource();
// 为此上下文初始化事件广播者
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean
onRefresh();
// 检查侦听器bean并注册
registerListeners();
// 实例化所有非懒加载的剩余单例
finishBeanFactoryInitialization(beanFactory);
// 完成刷新
finishRefresh();
}


// ================= 异常处理 =================
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例
destroyBeans();
// 重置上下文的激活状态
cancelRefresh(ex);
throw ex;
}
finally {
// 重置内部的一些元数据缓存
resetCommonCaches();
}
}
}

从总体来看,该方法描述的初始化过程大概分为三步:

  • [x] 上下文的初始化;
  • [x] BeanFactory 初始化;
  • [x] 事件,Bean及其他配置的初始化;

笔者将基于 spring 源码 5.2.x 分支,分别通过五篇文章从源码分析 spring 容器的初始化过程。

本文是其中的第三篇文章,将介绍上下文中事件,Bean及其他配置的初始化。

相关文章:

  • 深入理解Spring容器初始化(一):上下文的初始化

  • 深入理解Spring容器初始化(二):BeanFactory的初始化

  • 深入理解Spring容器初始化(三):事件及其他配置的初始化

    1. 一、初始化数据源

      调用 AbstarctApplicationContext.initMessageSource() 用于初始化上下文所使用的数据源对象 MessageSource,这个配置用于支持国际化的信息处理,一般情况下比较少会直接去配置它:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      protected void initMessageSource() {
      ConfigurableListableBeanFactory beanFactory = getBeanFactory();
      // 如果当前上下文否存在名为“messageSource”的Bean
      if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
      // Make MessageSource aware of parent MessageSource.
      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
      // 若父容器没有MessageSource,就把它设置为父容器的MessageSource
      HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
      if (hms.getParentMessageSource() == null) {
      // Only set parent context as parent MessageSource if no parent MessageSource
      // registered already.
      hms.setParentMessageSource(getInternalParentMessageSource());
      }
      }
      if (logger.isTraceEnabled()) {
      logger.trace("Using MessageSource [" + this.messageSource + "]");
      }
      }
      else {
      // 不存在就尝试获取父容器的MessageSource
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
      if (logger.isTraceEnabled()) {
      logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
      }
      }
      }

      二、初始化事件广播者

      调用 AbstarctApplicationContext.initApplicationEventMulticaster() 是初始化 spring 事件机制的第一步,它的作用很简单:

      如果当前 BeanFactory 有名为 “applicationEventMulticaster”ApplicationEventMulticaster,就把它设置为当前上下文的事件广播器,否则就创建并在 BeanFactory 中注册一个SimpleApplicationEventMulticaster 实例作为当前上下文的事件广播器。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      protected void initApplicationEventMulticaster() {
      ConfigurableListableBeanFactory beanFactory = getBeanFactory();
      // 是否存在“applicationEventMulticaster”这个Bean
      if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      // 如果存在就把它设置为当前上下文的事件广播器
      this.applicationEventMulticaster =
      beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
      logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
      }
      else {
      // 没有就创建一个SimpleApplicationEventMulticaster作为当前上下文的事件广播器
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
      logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
      "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
      }
      }

      三、初始化特殊Bean

      AbstarctApplicationContext.onRefresh() 用于在完成上下文与 BeanFactory 初始化后去初始化一些特殊的 Bean,其实从方法名就可以看出来,这个方法主要是作为上下文初步刷新完毕后的回调使用。

      AbstarctApplicationContext 中只提供了空实现,实际上也只有很少的实现类会去重新实现这个方法,至少在 5.2.x 里面,关于这个方法的有用实现只有:

      1
      UiApplicationContextUtils.initThemeSource(this)

      该代码用于初始化一些 spring 的“主题资源”,一般用于配合消息国际化进行一些处理。

      四、注册事件监听器

      当消息和事件相关的内容都准备就绪后,上下文会调用 AbstarctApplicationContext.registerListeners 方法以注册事件监听器 ApplicationListener

      这一步代码不动,实际上逻辑也很简单:

      • 向事件广播器注册已经被注册的上下文中的监听器;
      • 向事件广播器注册还没有被实例化的监听器的 BeanName
      • 发布一些早期事件;
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      protected void registerListeners() {
      // 向事件广播器注册已经被注册的上下文中的监听器
      for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
      }

      // 向事件广播器注册指定的监听器,不过这里只注册BeanName,
      // 因为有些监听器Bean是由FactoryBean生产的,而在这里FactoryBean实际上还没被生成出来
      String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
      for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
      }

      // 发布一些早期事件
      Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
      this.earlyApplicationEvents = null;
      if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
      getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
      }
      }

      这里有两个比较有意思的地方:

      • getApplicationListeners 获取的监听器实际上也是通过一个名为 EventListenerMethodProcessorBeanFactoryPostProcessor 注册到上下文的;
      • 注册 BeanName 而不是直接注册 Bean 这一点是为了迁就 FactoryBean。实际上在初始化 BeanFactory 的时候,调用 BeanFactoryPostProcessor 和注册 BeanPostProcessor 也都专门对此进行了处理;

      五、实例化工厂中的Bean

      当调用 AbstarctApplicationContext.finishBeanFactoryInitialization 的时候,spring 会根据 BeanFactory 中已经注册的 BeanDefinition 实例化所有非懒加载的单例 Bean

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
      // 为BeanFactory设置ConversionService
      // 该接口为spring转换器体系的入口
      if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
      beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
      beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
      }

      // 注册一个StringValueResolver,没有就从上下文的环境对象中获取
      // 该解析器用于解析配置文件中的一些占位符以及SpEL表达式
      if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
      }

      // 若存在AOP使用的支持类加载时织入切面逻辑的类加载器,则优先将该Bean初始化
      String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
      for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
      }

      // 由于类加载器已经初始化完成,所以可以停用临时的类加载器了
      beanFactory.setTempClassLoader(null);

      // 锁定当前工厂的配置
      beanFactory.freezeConfiguration();

      // 初始化剩余未初始化的非懒加载单例Bean
      beanFactory.preInstantiateSingletons();
      }

      这个方法总共干了五件事:

      • BeanFactory 设置类型转换服务 ConversionService
      • BeanFactory 设置占位符转换器 StringValueResolver
      • 禁用临时的类加载器,若有则启用支持类加载时织入切面逻辑的类加载器;
      • 锁定当前 BeanFactory 的配置;
      • 初始化剩余未初始化的非懒加载单例 Bean

      这里我们重点关注 BeanFactory.preInstantiateSingletons() 方法,此处是实际上完成 Bean 初始化的代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      public void preInstantiateSingletons() throws BeansException {
      if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
      }

      // Iterate over a copy to allow for init methods which in turn register new bean definitions.
      // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
      List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

      // 遍历beanName,若BeanName是可以实例化的非懒加载单例Bean,则将其实例化
      for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      // 如果是FactoryBean
      if (isFactoryBean(beanName)) {
      Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
      if (bean instanceof FactoryBean) {
      FactoryBean<?> factory = (FactoryBean<?>) bean;
      boolean isEagerInit;
      // 类型为SmartFactoryBean,则是否立刻实例化由SmartFactoryBean.isEagerInit()决定
      if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
      isEagerInit = AccessController.doPrivileged(
      (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
      getAccessControlContext());
      }
      else {
      // 类型不为SmartFactoryBean,则不立刻实例化
      isEagerInit = (factory instanceof SmartFactoryBean &&
      ((SmartFactoryBean<?>) factory).isEagerInit());
      }
      if (isEagerInit) {
      getBean(beanName);
      }
      }
      }
      else {
      // 实例化bean
      getBean(beanName);
      }
      }
      }

      // 获取所有实现了SmartInitializingSingleton接口的Bean,调用Bean初始化后回调afterSingletonsInstantiated
      for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
      SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
      if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      smartSingleton.afterSingletonsInstantiated();
      return null;
      }, getAccessControlContext());
      }
      else {
      smartSingleton.afterSingletonsInstantiated();
      }
      }
      }
      }

      这一步主要干了两件事:

      • 如果是允许实例化的非懒加载普通 Bean,就直接初始化;
      • 如果是允许实例化的非懒加载 FactoryBean,则判断它是否是 SmartFactoryBean
        1. 如果不是,则放弃直接初始化;
        2. 如果是,则根据 SmartFactoryBean.isEagerInit() 判断是否要直接初始化;
      • 初始化所有可初始化的 Bean 后,如果这些 Bean 实现了 SmartInitializingSingleton 接口,则调用该接口提供的回调函数;

      这里需要注意两点:

      • BeanFactory.getBean() 实际才是最终完成 BeanFactory 创建 Bean 实例操作的方法,在这个方法中将根据 BeanDefinition 完成各自依赖的自动装配、Bean 的后置处理等操作,三级缓存也是在这个时候使用的,这部分的内容将会在后续另起一篇文章分析;
      • 此处仅预加载了 FactoryBean,而没有懒加载 FactoryBean 里面的 Bean,因此 FactoryBean 提供的 Bean 总是懒加载的;
      • SmartInitializingSingleton 接口用于提供 BeanFactory 在初始化全部非懒加载 Bean 时调用的回调函数;

      至此,BeanFactory 中所有可以预先初始化的 Bean 都完成的初始化,我们已经可以通过 BeanFactory 正常的去获取 Bean 了。

      六、完成刷新

      AbstractApplicationContext.finishRefresh() 是完成容器刷新的最后一步,它跟 AbstractApplicationContext.onRefresh() 一样是一个钩子方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      protected void finishRefresh() {
      // 清空资源缓存
      clearResourceCaches();

      // 初始化上下文的生命周期处理器
      initLifecycleProcessor();

      // 调用上下文的生命周期处理器
      getLifecycleProcessor().onRefresh();

      // 发布上下文刷新完毕事件
      publishEvent(new ContextRefreshedEvent(this));

      // 注册用于支持通过JMX管理spring的组件,这里不过多分析,
      // 关于JMX具体可以参考这篇文章:https://www.wdbyte.com/java/jmx.html#_3-2-%E8%B5%84%E6%BA%90%E4%BB%A3%E7%90%86-mbean-server
      LiveBeansView.registerApplicationContext(this);
      }

      1、清空上下文资源缓存

      1
      2
      3
      public void clearResourceCaches() {
      this.resourceCaches.clear();
      }

      2、初始化上下文的生命周期处理器

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      protected void initLifecycleProcessor() {
      ConfigurableListableBeanFactory beanFactory = getBeanFactory();
      // 若存在名为“lifecycleProcessor”的bean,则设置为生命周期处理器
      if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
      this.lifecycleProcessor =
      beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
      if (logger.isTraceEnabled()) {
      logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
      }
      }
      // 若不存在名为“lifecycleProcessor”的bean,则创建一个DefaultLifecycleProcessor并设置为生命周期处理器
      else {
      DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
      defaultProcessor.setBeanFactory(beanFactory);
      this.lifecycleProcessor = defaultProcessor;
      beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
      if (logger.isTraceEnabled()) {
      logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
      "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
      }
      }
      }

      3、生命周期处理

      这里需要着重研究一下生命周期处理器的调用。

      getLifecycleProcessor().onRefresh() 这一步,将会获取上一步设置到上下文中的 LifecycleProcessor 然后调用:

      1
      2
      3
      4
      5
      6
      7
      8
      // AbstraceApplicationContext.getLifecycleProcessor()
      LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
      if (this.lifecycleProcessor == null) {
      throw new IllegalStateException("LifecycleProcessor not initialized - " +
      "call 'refresh' before invoking lifecycle methods via the context: " + this);
      }
      return this.lifecycleProcessor;
      }

      这里我们以默认的生命周期处理器 DefaultLifecycleProcessor 为例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      @Override
      public void onRefresh() {
      startBeans(true);
      this.running = true;
      }

      private void startBeans(boolean autoStartupOnly) {
      // 获取所有实现了Lifecycle接口的Bean,并按阶段分组装到不同的LifecycleGroup里
      Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
      Map<Integer, LifecycleGroup> phases = new HashMap<>();
      lifecycleBeans.forEach((beanName, bean) -> {
      // 同时满足下述条件的Bean不会被处理
      // 1.入参的autoStartupOnly为true
      // 2.bean实现了SmartLifecycle接口
      // 3.SmartLifecycle.isAutoStartup()方法返回false
      if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
      // 若实现了SmartLifecycle接口,则返回SmartLifecycle.getPhase(),否则默认返回0
      int phase = getPhase(bean);
      LifecycleGroup group = phases.get(phase);
      if (group == null) {
      group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
      phases.put(phase, group);
      }
      group.add(beanName, bean);
      }
      });

      // 按阶段从小到大排序,依次处理
      if (!phases.isEmpty()) {
      List<Integer> keys = new ArrayList<>(phases.keySet());
      Collections.sort(keys);
      for (Integer key : keys) {
      phases.get(key).start();
      }
      }
      }

      可以看到,这里针对 SmartLifecycle 接口的实现类做了很多特殊化的处理,默认情况下:

      • 实现了 SmartLifecycle 接口的 Bean,需要保证 SmartLifecycle.isAutoStartup 返回 true 才会被处理;
      • 没实现 SmartLifecycle 接口,但是实现了 Lifecycle 接口的 Bean 会被直接处理;

      并且,在处理 Bean 的时候,还会根据声明周期“阶段”按顺序从小到大排序:

      • 实现了 SmartLifecycle 接口的 Bean,按照 SmartLifecycle.getPhase 返回值排序从小到大执行;
      • 没实现 SmartLifecycle 接口,但是实现了 Lifecycle 接口的 Bean ,“阶段”视为 0,会被最先处理;

      4、发布上下文刷新完毕事件

      这个操作其实也很简单,其实就是调用时间广播器推送一个 ContextRefreshedEvent 事件:

      1
      2
      3
      4
      5
      public class ContextRefreshedEvent extends ApplicationContextEvent {
      public ContextRefreshedEvent(ApplicationContext source) {
      super(source);
      }
      }

      这个事件里唯一一个参数就是上下文本身。

      这一部分主要逻辑在事件推送上,后续会在专门的文章分析 spring 提供的事件机制,这里就不过多展开。

      总结

      本文内容比较零散,主要干三件事:

      • 初始化消息源相关组件:
        1. initMessageSource:初始化上下文使用的消息源;
        2. onRefresh:上下文刷新时的回调函数,但是一般只用于加载 ThemeSource
      • 初始化事件相关组件:
        1. initApplicationEventMulticaster:初始化事件广播器;
        2. registerListeners:注册容器中的事件监听器 ApplicationListener
      • 初始化 BeanFactory 中所有非抽象的非懒加载 Bean
      • 完成刷新:
        1. 清空上下文中的资源缓存;
        2. 初始化并调用 Bean 生命周期处理器;
        3. 发布上下文刷新时间;
        4. 注册并初始化用于支持 JMX 的组件;

      Untitled-2022-09-25-1044

0%