3.0、Spring源码学习:认识 AbstractApplicationContext.refresh()

文章目录

      • 前言
      • 所有初始化 Spring 容器的操作都会调用这个 refresh() 方法
      • refresh() 方法 修改 active flag 为true
      • 提供一个新入口
        • GenericApplicationContext
        • refresh() 的 UML 关系图
      • 进入源码
        • refresh()
      • 对 refresh()中关键代码的解读
        • prepareRefresh();
        • ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        • prepareBeanFactory(beanFactory);
        • postProcessBeanFactory(beanFactory);
        • 后置处理器的概念
          • invokeBeanFactoryPostProcessors(beanFactory);
          • registerBeanPostProcessors(beanFactory);
        • initMessageSource();
        • initApplicationEventMulticaster();
        • onRefresh();
        • registerListeners();
        • finishBeanFactoryInitialization(beanFactory);
        • finishRefresh();
        • destroyBeans();
        • cancelRefresh(ex);
        • resetCommonCaches();
      • 参考资料

前言

体能状态先于精神状态,习惯先于决心,聚焦先于喜好

所有初始化 Spring 容器的操作都会调用这个 refresh() 方法

上一篇文章提到类这一点 2、Spring源码学习:认识加载 xml 文件的 ClassPathXmlApplicationContext
从其定义(org.springframework.context.ConfigurableApplicationContext.refresh() )来看,用于加载或者刷新来自 XML 文件、properties 文件 或者关系数据库的配置
是一个在开始阶段调用的方法,简单说,其负责加载的(non-lazy-init)单例 bean 要么全部成功,要么全部失败
refresh()的实现方法位于 org.springframework.context.support.AbstractApplicationContext

//进去 debug 跟踪 refresh()方法即可
ApplicationContext application=new ClassPathXmlApplicationContext("classpath:applicationContext2.xml");

refresh() 方法 修改 active flag 为true

refresh() 内部调用方法 org.springframework.context.support.AbstractApplicationContext.prepareRefresh(
准备刷新上下文,设置开始时间和 active flag 未true
这个 active flag 是作为 是否需要刷新 applicatonContext 对象的标志

提供一个新入口

GenericApplicationContext

因为 在 Spring 容器加载的初期, refresh()方法都会被调用,本文开启了另一个入口
org.springframework.context.support.GenericApplicationContext
这个类可以为我们提供更灵活的配置,即手动去设置配置文件,以及手动调用 refresh() 方法

@Test
public void testRefresh() {
	//org.springframework.context.support.GenericApplicationContext
	GenericApplicationContext ctx = new GenericApplicationContext();
	XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
	//文件位于 src/main/resources 目录下
	xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
	PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
	propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
	//从这里进去源码
	ctx.refresh();
	//MyBean myBean = (MyBean) ctx.getBean("myBean");
}

refresh() 的 UML 关系图

用于表示 refresh() 方法与其他接口或类关系的UML 关系图

3.0、Spring源码学习:认识 AbstractApplicationContext.refresh()_第1张图片

进入源码

refresh()

简单来说,Spring 创建一个webApplicationContext 之后,需要进行 refresh()动作,其中最主要的就是加载指定的 Spring 的配置文件。
并且将在这个方法中修改if (!cwac.isActive()) {判断是是否激活标志 传送门
加载或者刷新持久化对配置信息,该配置可能是一个XML 文件,properties 文件,或者关系型数据库
由于这是一个启动阶段对方法,如果启动失败对化,所有已经被创建对单例bean都需要被销毁,以避免不稳定对资源出现.换句话说,这个方法被调用完毕后,要么所有的单例bean被加载到(上下文),要么一个都没有被加载.

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//刷新之前的准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
		//这里将beanFactory 是否激活修改为 true
		prepareRefresh();
		
		// 通知子类刷新自己的 BeanFactory (将 bean定义转化为 beandefination 对象,添加到 BeanFactory,但是未实例化)
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		// 准备 beanFactory 供上下文使用(context,看具体实现的子类,设置ClassLoader,Spel解析器,忽略部分接口的注入,实例化部分类,添加后置处理器-postprocess)
		prepareBeanFactory(beanFactory);
		try {
			// Allows post-processing of the bean factory in context subclasses.
			//模版方法:允许子类对 beanFactory 进行 后续处理(post-processing),webXmlApplicationContext 设置了scope等参数
			postProcessBeanFactory(beanFactory);
			// 实例化、注册并调用 beanFactory 中作为工厂处理器的 后置处理器bean,如 PropertyPlaceholderConfigurer(处理占位符)
			invokeBeanFactoryPostProcessors(beanFactory);
			
			// 实例化和注册beanFactory中扩展了BeanPostProcessor的后置处理器bean,如 AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			// 初始化 消息国际化工具类 MessageSource
			initMessageSource();

			// Initialize event multicaster for this context.
			// 初始化 事件 组播处理器
			initApplicationEventMulticaster();

			// 模版方法:初始化子类上下文中被特殊定义的bean;Spring 提供的是一个空方法,供子类扩展
			onRefresh();

			// 检查并注册事件监听器bean,广播early application events
			registerListeners();

			// 实例化所有non-lazy-init(非懒加载的) 的单例bean,实例化的过程各种 BeanPostProcessor 开始起作用
			finishBeanFactoryInitialization(beanFactory);

			// 最后一步:发布相应的事件-上下文刷新工作完成了
			//清除上下文资源缓存(如扫描中的ASM元数据);初始化上下文的生命周期处理器,并刷新(找出Spring容器中实现了Lifecycle接口的bean并执行start()方法)。发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - "+"cancelling refresh attempt: " + ex);
			}
			//catch逻辑:销毁已经被创建的单例 bean,避免不稳定资源的出现
			destroyBeans();

			//catch逻辑:重置 ‘active’标志
			cancelRefresh(ex);

			// 继续抛出异常给调用者
			throw ex;
		}

		finally {
			// finally逻辑:重置 Spring's core 的缓存信息,因为我们可能不会再用到这些单例bean的元数据信息了
			resetCommonCaches();
		}
	}
}

对 refresh()中关键代码的解读

prepareRefresh();

org.springframework.context.support.AbstractApplicationContext.prepareRefresh(
准备刷新上下文,设置开始时间和 active flag 以便于开始任何配置文件的初始化动作。
这里的 active flag 默认为 false,一般作为 新创建 webApplicationContext 对象是否刷新的标志 如 传送门

	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}
		// 初始化任何通配符匹配的文件,你可以任务该方法之后,操作系统相关、JVM相关信息都被加载了,准备的参数可以通过 getEnvironment() 来获取
		initPropertySources();

		//检测必须参数的非空性,通过 ConfigurablePropertyResolver#setRequiredProperties 设置
		//debug发现,默认情况该方法没啥用-没有需要检测的从参数
		getEnvironment().validateRequiredProperties();

		//实例化LinkedHashSet,允许早期的 ApplicationEvents 集合在 multicaster 可用时被发布
		this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
	}

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

本方法用于将配置文件中的bean加载到 beanDefination 中,然后将beanDefination 放入到 beanFactory,但是需要注意到是,只是加载了 bean到定义信息,还没有进行注入、实例化等工作.
限于篇幅,单独起一篇文章
3.2ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

3.0、Spring源码学习:认识 AbstractApplicationContext.refresh()_第2张图片

prepareBeanFactory(beanFactory);

本方法用于设置 beanFactory 的类加器、SpEL解析器、bean的属性编辑器、特殊接口的免自动注入和特殊类型的指定注入,环境对象设置为单例
限于篇幅,单独写一篇文章
3.3 prepareBeanFactory(beanFactory);

postProcessBeanFactory(beanFactory);

代码运行到这里,Spring 上下文已经将基本的 beanFactory 和 beanDefination 准备好了。
该方法允许子类对 beanFactory 进行进一步的后置处理;
该方法默认为空方法,允许子类根据需要选择是否覆盖重写,体现了模板方法模式;
具体来说,如果子类为 ClassPathApplicationContext ,那么这个方法依旧是一个空方法

后置处理器的概念

Spring 中的事件允许不同的bean之间的信息交换,体现了观察者模式。
事件可以是既定的事件,也可以是自定义的事件,事件发布后由多播处理器统一处理,对所有的监听器进行事件转发——该过程可以是多线程异步的。更详细的介绍可以看下文
Spring中的事件发布和处理

invokeBeanFactoryPostProcessors(beanFactory);

该方法与 beanFactory 相关的后置处理器的初始化、注册和调用
重点关注 ConfigurationClassPostProcessor 这个后置处理器,用于处理代码中的
@Component、@Configuration、@ComponentScan 、@Bean 注解的处理
可以理解为,Spring Bean 可以来自于 XML定义,也可以来自 Java 代码中的定义.

registerBeanPostProcessors(beanFactory);

该方法仅仅用于与 普通 Spring bean 相关的后置处理器的处理

initMessageSource();

配置 i18n 即国际化资源
i18n项目源码

initApplicationEventMulticaster();

初始化应用的事件多播处理器,事件发布后由该处理器统一进行处理

onRefresh();

默认是空实现,给子类扩展的空间,又是模版方法模式呦

registerListeners();

注册监听器,比如上下文完成刷新事件
也可以自定义监听器,由于多播处理器并不会区分监听器,所以需要监听器自己区分不同的事件进行针对性处理。

finishBeanFactoryInitialization(beanFactory);

finishRefresh();

destroyBeans();

cancelRefresh(ex);

resetCommonCaches();

参考资料

[1]、https://www.jianshu.com/p/bede81fad45c

你可能感兴趣的:(Spring,源码,refresh,#,Spring,源码学习)