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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/bestcxx/article/details/90517999

前言

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

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

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

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 关系图

在这里插入图片描述

进入源码

refresh()

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

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

		// Prepare the bean factory for use in this context.
		// 准备 beanFactory 供上下文使用(context,看具体实现的子类)
		prepareBeanFactory(beanFactory);
		try {
			// Allows post-processing of the bean factory in context subclasses.
			//允许子类对 beanFactory 进行 后续处理(post-processing)
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			// 调用上下文中注册的bean 工厂处理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			// 注册 使用拦截方式 对 bean 进行后续处理的b ean
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			// 初始化 上下文 的 消息资源
			initMessageSource();

			// Initialize event multicaster for this context.
			// 初始化 上下文 的事件广播器
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			// 初始化子类上下文中被特殊定义的bean;Spring 提供的是一个空方法,供子类扩展
			onRefresh();

			// Check for listener beans and register them.
			// 检查并注册事件监听器bean
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			// 实例化所有non-lazy-init(非延迟加载的) bean
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			// 最后一步:发布相应的事件-上下文刷新工作完成了
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - "+"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			//销毁一ing被创建的单例 bean,避免不稳定资源的出现
			destroyBeans();

			// Reset 'active' flag.
			//重置 ‘active’标志
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			// 重置 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();

限于篇幅,单独写了一篇文章
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

prepareBeanFactory(beanFactory);

postProcessBeanFactory(beanFactory);

invokeBeanFactoryPostProcessors(beanFactory);

registerBeanPostProcessors(beanFactory);

initMessageSource();

initApplicationEventMulticaster();

onRefresh();

registerListeners();

finishBeanFactoryInitialization(beanFactory);

finishRefresh();

destroyBeans();

cancelRefresh(ex);

resetCommonCaches();

猜你喜欢

转载自blog.csdn.net/bestcxx/article/details/90517999