Loading...
墨滴

CoderLi

2021/03/22  阅读:38  主题:嫩青

ApplicationContext 源码分析

BeanFactory 继承图

Spring Boot 中 ApplicationContext 的继承图

挺有意思、顶层接口、Configurable、Abstract,然后下面就是比较具体场景的实现类,Environment 也是这样的结构。

  • ApplicationContext
  • ConfigurableApplicationContext
  • AbstractApplicationContext
  • GenericApplicationContext
  • GenericWebApplicationContext
  • ServletWebServerApplicationContext
  • AnnotationConfigServletWebServerApplicationContext & XmlServletWebServerApplicationContext

Spring 中 ApplicationContext的继承图

源码分析

ClassPathXmlApplicationContext classPathXmlApplicationContext =
      new ClassPathXmlApplicationContext("coderLi.xml");
<bean class="com.demo.data.Cat" id="cat"/>
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, truenull);
}

public ClassPathXmlApplicationContext(
  String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

  throws BeansException 
{
  super(parent);
  setConfigLocations(configLocations);
  if (refresh) {
    refresh();
  }
}

将要放入 Spring 的资源文件也就是 beanDefinition 解释之后赋值给 configLocations 变量保存

public void setConfigLocations(@Nullable String... locations) {

   if (locations != null) {
      Assert.noNullElements(locations, "Config locations must not be null");
      this.configLocations = new String[locations.length];
      for (int i = 0; i < locations.length; i++) {
         // 解释给定路径,比如说 路径中包含某些特殊符号 ${var}
         this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}
protected String resolvePath(String path) {
  return getEnvironment().resolveRequiredPlaceholders(path);
}
@Override
public ConfigurableEnvironment getEnvironment() {
  if (this.environment == null) {
    this.environment = createEnvironment();
  }
  return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
  return new StandardEnvironment();
}

resolvePath 会搜寻匹配系统变量并进行替换。关于 Environment 的可以看我另一篇文章:Environment 概述

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {

      prepareRefresh();

      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      prepareBeanFactory(beanFactory);

      try {
        
         postProcessBeanFactory(beanFactory);
     
         invokeBeanFactoryPostProcessors(beanFactory);

         registerBeanPostProcessors(beanFactory);

         initMessageSource();

         initApplicationEventMulticaster();

         onRefresh();

         registerListeners();

         finishBeanFactoryInitialization(beanFactory);

         finishRefresh();
      } catch (BeansException ex) {
        
         destroyBeans();

         cancelRefresh(ex);
         throw ex;
      } finally {
         resetCommonCaches();
      }
   }
}
  • prepareRefresh 准备刷新的上下文环境
  • obtainFreshBeanFactory 创建 beanfactory 并加载注册 beanDefinition
  • prepareBeanFactory 对 beanFactory 各种功能进行填充
  • invokeBeanFactoryPostProcessors 对 BeanFactoryPostProcessor的bean 进行回调
  • registerBeanPostProcessors 注册 BeanPostProcessors 到 BeanFactory 中
  • initMessageSource 国际化
  • initApplicationEventMulticaster 创建事件广播器
  • onRefresh 空方法、给子类扩展
  • registerListeners 注册事件监听器
  • finishBeanFactoryInitialization 初始化剩下的单例 非延迟初始化的
  • finishRefresh 完成刷新、同志生命周期处理器 lifecycleProcessor 刷新过程、并发布 contextRefreshEvent
  • resetCommonCaches 清理使用到的一些内存缓存

prepareRefresh

protected void prepareRefresh() {
 
  // .......
  // 初始化属性源
   initPropertySources();
 // 对属性进行验证
   getEnvironment().validateRequiredProperties();

}

initPropertySources 这个方法默认是空方法、交由子类去扩展。在 GenericWebApplicationContext 中、就将原来放入 Environment 对象中的 Servlet Context 和 Servlet Config 两个属性源占位符进行替换。详细可以看 Environment 概述

@Override
protected void initPropertySources() {
   ConfigurableEnvironment env = getEnvironment();
   if (env instanceof ConfigurableWebEnvironment) {
      ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
   }
}

obtainFreshBeanFactory

@Override
protected final void refreshBeanFactory() throws BeansException {
 .........
   try {
      // 创建 DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 为了序列化的时候、指定 id
      beanFactory.setSerializationId(getId());
      // 定制 beanFactory
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
    .....
   }
}

createBeanFactory 去创建 DefaultListableBeanFactory。

customizeBeanFactory 主要去设置两个属性、一个是是否允许 BeanDefinition 覆盖。一个是是否允许循环依赖。

loadBeanDefinitions

将第一步处理好的资源文件路径拿出来进行读取和注册到 BeanDefinitionRegister 中。关于这个部分可以看文章 Spring 容器初始化

prepareBeanFactory

  • 设置 BeanClassLoader、默认是获取线程中的 ClassLoader

    Thread.currentThread().getContextClassLoader();

  • 设置 SPEL 的解释器

  • 增加一个属性编辑器的注册点

  • 实现 Aware 接口的注入功能。详细可以看以前的文章 Spring Aware 介绍

  • 然后就是 ignoreDependencyInterface 相关的、可以看下

    https://www.jianshu.com/p/3c7e0608ff1f

    https://www.codenong.com/cs106291653/

  • registerResolvableDependency 绑定注入类型和对应的 bean

  • 增加一个 BeanPostProcessor、这个类主要做了一件事就是将 ApplicationListener 对象加入到 ApplicationContext 中保存起来

往后就是完 BeanFactory 中塞一些对象

所以我们可以通过注解到方式获取对象的对象

postProcessBeanFactory

默认实现方法是空实现、可以在这个方法内对 beanFactory 对一些信息进行修改、这个时机、刚刚好是所有 BeanDefinition 注册完毕、但是没有被实例化。你可以在这个方法中增加 BeanPostProcessor等。

看看其中的一两个子类实现

这个类似于上面的 ApplicationContextAwareProcessor 的功能。

另一个子类、做的事情也是类似的、BootstrapContextAwareProcessor 使用的比较少、有机会再看看吧后续。

invokeBeanFactoryPostProcessors

看名字就可以猜出是激活 BeanFactoryPostProcessor 的

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}

直接进入 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法

代码很长、大概说一下流程

首先判断beanFactory是否是 BeanDefinitionRegistry 、如果是则则判断参数重的 BeanFactoryPostProcessor是否 BeanDefinitionRegistryPostProcessor、如果是则调用 postProcessBeanDefinitionRegistry 方法。

后续则去 BeanFactory中找出对应的 BeanDefinitionRegistryPostProcessor 实例、这其中先是 PriorityOrdered 的、然后是 Ordered 的、最后是正常的。

然后才是去去调用 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。

最后也是类似的去 beanFactory 中找 BeanFactoryPostProcessor 的实例。这其中先是 PriorityOrdered 的、然后是 Ordered 的、最后是正常的。

流程上不复杂、考虑的情况有点多、所以代码篇幅有点长。

registerBeanPostProcessors

这个方法也是类似的、从 beanFactory 中捞对应的bean 出来注册然后注册、顺序 方面也是 PriorityOrdered然后Ordered、然后正常。里面也涉及到了对 MergedBeanDefinitionPostProcessor 的注册、其实它是 BeanPostProcessor的子类。

initMessageSource

初始化消息资源、国际化相关的,不太熟悉

protected void initMessageSource() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
       if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
         if (hms.getParentMessageSource() == null) {
            hms.setParentMessageSource(getInternalParentMessageSource());
         }
      }
   } else {
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
   }
}

initApplicationEventMulticaster

注册一个事件广播器、这个也没啥说的

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
   } else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
   }
}

onRefresh

模版方法、给子类去扩展的方法。

registerListeners

注册监听器

protected void registerListeners() {
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.classtruefalse);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

finishBeanFactoryInitialization

这个方法主要去初始化剩下非延迟初始化的 bean。 涉及到 ConversionService 、以及冻结 BeanDefinition、最后去调用 BeanFactory 的 preInstantiationSingletons方法 这个方法主要是获取所有的 BeanDefinition 然后调用 getBean 方法去实例化。如果是 FactoryBean 则会根据是否是 eager 去判断是否获取实际的 Bean。 最后会去对实现了 SmartInitializingSingleton 的回调接口。

finishRefresh

  1. 清理 Resource 资源
  2. 初始化 LifecycleProcessor
  3. 调用 LifecycleProcessor 的 on Refresh 方法
  4. 发布 ContextRefreshEvent

resetCommonCaches

这个方法在 finally 代码块中。主要是清理各种缓存资源,比如说 Spring 自定义了一个 Introspector 的检查。还有各种的其他缓存。

总结

其实整一个 refresh 过程还是挺简单的、从大体上来看、与我们直接使用 BeanFactory 的时候相比、多了一些扩展性的东西、但是这些扩展的地方、都是原本Spring 提供给我们、我们自己也可以进行扩展的。

https://www.codenong.com/cs106291653/

CoderLi

2021/03/22  阅读:38  主题:嫩青

作者介绍

CoderLi