ApplicationContext #refresh() 解析

355 阅读5分钟

这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

作为spring 容器中很重要的一个容器ApplicationContext 重要程度: 可以给五颗星了!!! 宏观了解:

ApplicationContext 相比较 BeanFactory 扩展的实在是太多了.ApplicationContext 不仅继承了 BeanFactory 的两个扩展接口,还继承了其它几个接口

FeatureBeanFactoryApplicationContext
Bean instantiation/wiring —— Bean的实例化和属性注入YesYes
Integrated lifecycle management —— 生命周期管理NoYes
Automatic BeanPostProcessor registration —— Bean后置处理器的支持NoYes
Automatic BeanFactoryPostProcessor registration —— BeanFactory后置处理器的支持NoYes
Convenient MessageSource access (for internalization) —— 消息转换服务(国际化)NoYes
Built-in ApplicationEvent publication mechanism —— 事件发布机制(事件驱动)NoYes

概括:ApplicationContext 提供:

  • 用于访问应用程序组件的 Bean 工厂方法。继承自 ListableBeanFactory
  • 以通用方式加载文件资源的能力。继承自 ResourceLoader 接口。
  • 能够将事件发布给注册的监听器。继承自 ApplicationEventPublisher 接口。
  • 解析消息的能力,支持国际化。继承自 MessageSource 接口。
  • 从父上下文继承。在子容器中的定义将始终优先。例如,这意味着整个 Web 应用程序都可以使用单个父上下文,而每个 servlet 都有其自己的子上下文,该子上下文独立于任何其他 servlet 的子上下文。 图片.png

微观解读: 这里做一下介绍,并选取里面最重要的方法 #refersh 解读下: 共有12个方法,一开始看着头大,看的多了自然就会记下来了

// AbstractApplicationContext.java

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 准备刷新上下文环境
		prepareRefresh();

		// 创建并初始化 BeanFactory
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 填充BeanFactory功能
		prepareBeanFactory(beanFactory);

		try {
			// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
			postProcessBeanFactory(beanFactory);

			// 激活各种BeanFactory处理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
			registerBeanPostProcessors(beanFactory);

			// 初始化上下文中的资源文件,如国际化文件的处理等
			initMessageSource();

			// 初始化上下文事件广播器
			initApplicationEventMulticaster();

			// 给子类扩展初始化其他Bean
			onRefresh();

			// 在所有bean中查找listener bean,然后注册到广播器中
			registerListeners();

			// 初始化剩下的单例Bean(非延迟加载的)
			finishBeanFactoryInitialization(beanFactory);

			// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
			finishRefresh();
		} catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			//  销毁已经创建的Bean
			destroyBeans();

			// 重置容器激活标签
			cancelRefresh(ex);

			// 抛出异常
			throw ex;
		} finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

AbstractApplicationContext【掌握*】

这个类是 ApplicationContext 最最最最核心的实现类,没有之一AbstractApplicationContext 中定义和实现了绝大部分应用上下文的特性和功能

首先有始有终,有准备就有结束,所以第一个方法是prepareRefresh(),最后一个方法是finishRefresh 了解一下准备工作:

1.prepareRefresh: 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,如环境变量中必须设置某个值才能运行,否则不能运行

12.finishRefresh : 完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人

2.obtainFreshBeanFactory这个也蛮重要的,简单来说是创建并初始化 BeanFactory,加载配置文件并解析的动作就在这里面 ,包含了刷新BeanFactory ,然后获取 重点了解其中的#loadBeanDefinitions

protected final void refreshBeanFactory() throws BeansException {
    // 存在BeanFactory则先销毁
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        customizeBeanFactory(beanFactory);
        // 【1.3】加载配置文件
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    } // catch 
}

loadBeanDefinitions往下读下去就是# XmlBeanDefinitionReader加载配置文件,#doLoadBeanDefinitions - 读取配置文件,# parseBeanDefinitions - 解析xml,解析各种标签

  1. prepareBeanFactory 填充BeanFactory的功能

  2. postProcessBeanFactory()

  3. invokeBeanFactoryPostProcessors()

  4. registerBeanPostProcessors 即注册 BeanPostProcessor

    todo 这个值得细解

  5. initMessageSource 初始化上下文中的资源文件,如国际化文件的处理等

  6. initApplicationEventMulticaster 初始化上下文事件广播器

  7. onRefresh 给子类扩展初始化其他Bean

  8. registerListeners 在所有 bean 中查找 listener bean,然后注册到广播器中

11.finishBeanFactoryInitialization 初始化剩下的单例Bean(非延迟加载的),其中有最最关键的初始化bean的动作,实际上执行了getBean的doGetBean方法,其中包含了循环依赖的判断,这个之后在解析

小结 :

首先 ClassPathXmlApplicationContextrefresh 之前,会指定传入的 xml 配置文件的路径,执行 refresh 方法时,会初始化 BeanFactory ,触发 xml 配置文件的读取、加载和解析。其中 xml 的读取需要借助 XmlBeanDefinitionReader ,解析 xml 配置文件则使用 DefaultBeanDefinitionDocumentReader ,最终解析 xml 中的元素,封装出 BeanDefinition ,最后注册到 BeanDefinitionRegistry ,这个就是第一章所讲的容器BeanDefinition 的过程

bean “实例阶段”的生命周期包含步骤:

  1. bean 的实例化
  2. 属性赋值 + 依赖注入
  3. bean 的初始化生命周期回调
  4. bean 实例的销毁

在所有非延迟加载的单实例 bean 初始化之前,会先初始化所有的 BeanPostProcessor

ApplicationContextrefresh 方法中,finishBeanFactoryInitialization 步骤会初始化所有的非延迟加载的单实例 bean 。实例化 bean 的入口是 getBeandoGetBean ,该阶段会合并 BeanDefinition ,并根据 bean 的 scope 选择实例化 bean 的策略。

创建 bean 的逻辑会走 createBean 方法,该方法中会先执行所有 InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation 方法尝试创建 bean 实例,如果成功创建,则会直接调用 postProcessAfterInitialization 方法初始化 bean 后返回;如果 InstantiationAwareBeanPostProcessor 没有创建 bean 实例,则会调用 doCreateBean 方法创建 bean 实例。在 doCreateBean 方法中,会先根据 bean 的 Class 中的构造器定义,决定如何实例化 bean ,如果没有定义构造器,则会使用无参构造器,反射创建 bean 对象 这里只讲了第一部分哦