ApplicationContext 源码分析

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

网络异常,图片无法展示
|


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}, true, null);
}
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 相关的、可以看下

www.jianshu.com/p/3c7e0608f…

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.class, true, false);
   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 提供给我们、我们自己也可以进行扩展的。

目录
相关文章
|
15天前
|
XML Java 数据格式
BeanFactory 和 ApplicationContext 的区别
【10月更文挑战第24天】在 Spring 框架中,`BeanFactory` 和 `ApplicationContext` 是两个核心的容器接口。`BeanFactory` 提供基本的 Bean 管理功能,支持延迟加载,适用于轻量级应用和资源受限环境。`ApplicationContext` 则在 `BeanFactory` 基础上扩展了丰富的企业级功能,如国际化、事件处理和资源管理,适用于企业级和 Web 应用开发。两者各有特点,需根据具体需求选择使用。
|
6月前
|
Java Spring 容器
Spring底层原理之 BeanFactory 与 ApplicationContext
Spring底层原理之 BeanFactory 与 ApplicationContext
61 3
|
6月前
|
Java C++ Spring
深入Spring原理-1.BeanFactory与ApplicationContext的区别
深入Spring原理-1.BeanFactory与ApplicationContext的区别
93 0
|
11月前
|
XML Java 数据格式
[读书笔记]Spring中BeanFactory和ApplicationContext的联系和区别
[读书笔记]Spring中BeanFactory和ApplicationContext的联系和区别
50 0
|
Java Spring 容器
BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 和 ApplicationContext 有什么区别?
73 0
|
存储 Java Spring
Spring之Bean生命周期源码分析(一)1
Spring之Bean生命周期源码分析(一)
216 1
|
XML Java API
BeanFactory与ApplicationContext区别和Spring快速入门
BeanFactory与ApplicationContext区别和Spring快速入门
BeanFactory与ApplicationContext区别和Spring快速入门
|
Java Spring
Spring之Bean生命周期源码分析(二)2
Spring之Bean生命周期源码分析(二)
123 0
|
Java Spring
Spring之Bean生命周期源码分析(一)2
Spring之Bean生命周期源码分析(一)
161 0