【Spring源码核心篇-04】spring中refresh刷新机制的流程和实现

发布于:2024-11-29 ⋅ 阅读:(18) ⋅ 点赞:(0)

Spring源码核心篇整体栏目


内容 链接地址
【一】Spring的bean的生命周期 https://zhenghuisheng.blog.csdn.net/article/details/143441012
【二】深入理解spring的依赖注入和属性填充 https://zhenghuisheng.blog.csdn.net/article/details/143854482
【三】精通spring的aop的底层原理和源码实现 https://zhenghuisheng.blog.csdn.net/article/details/144012934
【四】spring中refresh刷新机制的流程和实现 https://zhenghuisheng.blog.csdn.net/article/details/144118337

如需转载,请附上链接:https://blog.csdn.net/zhenghuishengq/article/details/144118337

一,spring中refresh刷新机制

前面讲解了spring的核心思想AOP和IOC 的底层原理和实现,接下来讲解的是spring源码的核心机制 refresh 方法,不管是前面的aop或者是ioc,都是需要经过这个核心方法的,接下来详细的查看这个refresh这个方法。

如在创建AnnotationConfigApplicationContext ,内部就会涉及到这个refresh方法

public AnnotationConfigApplicationContext(String... basePackages) {
	this();
	scan(basePackages);
	refresh();
}

refresh方法的具体实现如下,刷新时会加一个synchronized锁保证同步,其基本流程如下,接下来在后文会对里面的每一个步骤做一个初步的解释

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
   	//1:准备刷新上下文环境
   	prepareRefresh();
   	//2:获取告诉子类初始化Bean工厂  不同工厂不同实现
   	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
   	//3:对bean工厂进行填充属性
   	prepareBeanFactory(beanFactory);
   	try {
   		// 第四:留个子类去实现该接口
   		postProcessBeanFactory(beanFactory);
   		// 调用我们的bean工厂的后置处理器. 1. 会在此将class扫描成beanDefinition  2.bean工厂的后置处理器调用
   		invokeBeanFactoryPostProcessors(beanFactory);
   		// 注册我们bean的后置处理器
   		registerBeanPostProcessors(beanFactory);
   		// 初始化国际化资源处理器.
   		initMessageSource();
   		// 创建事件多播器
   		initApplicationEventMulticaster();
   		// 这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
   		onRefresh();
   		//把我们的事件监听器注册到多播器上
   		registerListeners();
   		// 实例化我们剩余的单实例bean.
   		finishBeanFactoryInitialization(beanFactory);
   		// 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
   		finishRefresh();
   	}
   	catch (BeansException ex) {
   		destroyBeans();
   		cancelRefresh(ex);
   		throw ex;
   	}

   	finally {
   		resetCommonCaches();
   	}
   }
}

1,prepareRefresh方法

首先第一步是进入这个prepareRefresh预准备刷新的方法,对一些基础属性进行设置和初始化,其流程如下:

  • 首先第一步是设置一些状态,如设置close状态,active状态等
  • 第二步是这个 initPropertySources 方法,该方法是给子类去使用的,比如在springmvc中,就实现了这个方法,该方法位于 AbstractRefreshableWebApplicationContext 类中,这样springmvc就可以去xml中的获取配置环境以及系统参数了。该方法底层使用了模板方法模式
  • 第三步就是通过这个validateRequiredProperties方法用于验证环境中是否有某些属性,用来校验我们容器启动必须依赖的环境变量的值
  • 最后一步就是初始化一些监听器,以及一些早期的事件等
protected void prepareRefresh() {
	this.closed.set(false);
	this.active.set(true);
	initPropertySources();
	getEnvironment().validateRequiredProperties();
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}
	this.earlyApplicationEvents = new LinkedHashSet<>();
}

2,obtainFreshBeanFactory方法

obtainFreshBeanFactory方法的实现如下,其主要目的就是判断是否需要刷新这个beanFactory,以及最终返回一个 BeanFactory

在这里插入图片描述

刷新refreshBeanFactory的具体实现类有以下两种,一种是常规的上下文的实现类,一种是可以刷新的上下文实现类

在这里插入图片描述

两种底层实现不一致,如果是常规的 GenericApplicationContext 实现类,如果判断这个beanFactory已经加载,那么就是会直接抛异常,但是beanFactory在ApplicationContext初始化的时候就已经初始化beanfactory,因此这个实现类是不允许多次refresh的

在这里插入图片描述

如果是 AbstractRefreshableApplicationContext 实现类的话,那么底层就是允许多次refresh刷新的,就是在刷新前会将原来已有的beanFactory给销毁以及关闭,然后重新创建BeanFactory,以及加载refresh之前需要加载的一些BeanDefinition。如springmvc中,那么肯定是需要进行多次刷新的,那么就会实现这个类。

在这里插入图片描述

3,prepareBeanFactory方法

在第二步返回了一个beanFactory,那么第三步开始就是对这个bean工厂进行属性填充,那么就直接进入这个prepareBeanFactory方法流程

  • 这里首先做的就是设置BeanFactory的类加载器,此时为application应用类加载器;
  • 第二步就是设置BeanFactory就是设置一些spel表达式,如@Value注解中的表达式等
  • 第三步就是设置一个propertityEditor属性资源编辑器对,比如一些inputStream流等
  • 最后就是添加一个bean工厂的后置处理器,用于在处理ApplicationContextAware接口回调
//设置bean工厂的类加载器为当前application应用的加载器
beanFactory.setBeanClassLoader(getClassLoader());
//为bean工厂设置我们标准的SPEL表达式解析器对象StandardBeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//为我们的bean工厂设置了一个propertityEditor 属性资源编辑器对象(用于后面的给bean对象赋值使用)
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//注册了一个完整的ApplicationContextAwareProcessor 后置处理器用来处理ApplicationContextAware接口的回调方法
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

设置完以上的基础属性之后,前期会对一些aware进行一些忽略,如EnvironmentAware 方法等

在这里插入图片描述

随后就是注册一些解析依赖,就是一些map映射关系,比如BeanFactory类对应的依赖就是BeanFactory

在这里插入图片描述

随后就是在bean的后置处理器中,增加一个监听探测器

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

然后就是一些处理@AspectJ注解的实现

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

最后就是判断bean工厂中是否包含一些系统环境,系统属性等,如果不存在,那么就会手动的注册一个

在这里插入图片描述

4,postProcessBeanFactory方法

接下来就是进入第4个方法postProcessBeanFactory,顾名思义,就是BeanFactory的后置处理器,用于内部子类的一些扩展,和postProcessBean需要区分,一个是给BeanFactory用的,一个是给Bean用的。

postProcessBeanFactory方法如下,内部是一个空方法,主要是提供给子类去实现。其实现类如下,主要有4个核心的实现类,但是这几个实现类主要是跟web相关,如在springmvc中使用

在这里插入图片描述

来分析一个具体实现,如 AbstractRefreshableWebApplicationContext 类中具体实现,首先会提前增加一个servletContext相关的后置处理器,然后忽略一些Aware回调接口,最后去注册一些web的作用域,环境变量bean等

在这里插入图片描述

除了上面这个实现类之外,其他的一些实现类也是基于web这一块去实现的,更多的还是作用与springmvc以及springboot中,是这些组件中的一些扩展

5,invokeBeanFactoryPostProcessors方法

接下来来到第五个方法 invokeBeanFactoryPostProcessors ,也是在refresh中比较重要,内容比较多的一个方法。其底层实现主要如下,内部主要是通过这个PostProcessorRegistrationDelegate类调用实现

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

在这里插入图片描述

首先第一步就是判断bean工厂是否是BeanDefinitionRegistry的子实现类,是的话那么就会循环外部子类所注册的BeanFactoryPostProcessor,然后将这些postProcessor强制转换成BeanDefinitionRegistryPostProcessor,然后加入到list集合中

在这里插入图片描述

下面这段代码是接着上面的代码,先去容器中获取BeanDefinitionRegistryPostProcessor的bean的处理器名称,随后通过这些名称进行匹配,判断是否实现了 PriorityOrdered 优先级接口,随后通过这个sortPostProcessors方法进行排序,随后通过这个invokeBeanDefinitionRegistryPostProcessors方法进行bean定义的加载,比如一些@Import等等,最后进行排序和注册功能

在这里插入图片描述

依旧是接着上面的代码,依旧是去容器中获取BeanDefinitionRegistryPostProcessor的bean的处理器名称,然后这里实现的是判断是否实现了 @Ordered 接口,然后完成排序注册等

在这里插入图片描述

还是接着上面的这段代码,上面两段代码是处理带有优先级的,接下来的这段代码就是处理没有实现任何优先级的BeanDefinitionRegistryPostProcessor,然后进行排序,注册到registryProcessors里面

在这里插入图片描述

处理完以上的操作之外,最后进行bean工厂的后置处理器的操作,将上面的优先级进行BeanFactory后置处理器的实现,依次先执行 priorityOrdered 实现类,Ordered 实现类,最后就是没有实现优先级接口的实现类

//获取容器中所有的 BeanFactoryPostProcessor
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

//保存BeanFactoryPostProcessor类型实现了priorityOrdered
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//保存BeanFactoryPostProcessor类型实现了Ordered接口的
List<String> orderedPostProcessorNames = new ArrayList<>();
//保存BeanFactoryPostProcessor没有实现任何优先级接口的
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
	//processedBeans包含的话,表示在上面处理BeanDefinitionRegistryPostProcessor的时候处理过了
	if (processedBeans.contains(ppName)) {
		// skip - already processed in first phase above
	}
	//判断是否实现了PriorityOrdered 优先级最高
	else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
	}
	//判断是否实现了Ordered  优先级 其次
	else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
		orderedPostProcessorNames.add(ppName);
	}
	//没有实现任何的优先级接口的  最后调用
	else {
		nonOrderedPostProcessorNames.add(ppName);
	}
}
//  排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 先调用BeanFactoryPostProcessor实现了 PriorityOrdered接口的
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

//再调用BeanFactoryPostProcessor实现了 Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
	orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

//调用没有实现任何方法接口的
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
	nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

因此这个方法主要有两个作用,一个是完成所有bean的扫描,一个是完成BeanFactory的后置处理器的调用

6,registerBeanPostProcessors方法

接下来第六个方法registerBeanPostProcessors注册bean的后置处理器,在第五个方法中,完成了bean工厂的后支持处理器,接下来看一下内部是如何实现的

在这个方法中,首先第一步还是在bean工厂获取全部的bean的名称

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

在这个bean的后置处理器中,和扫描bean工厂的后后置处理器的方式一样,先过滤实现 priorityOrdered 注解的的bean,然后过滤出实现Ordered注解的bean,最后扫描没有任何优先级的bean

在这里插入图片描述

随后对priorityOrdered注解的bean进行排序和注册,最后加入到BeanFactory容器中

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

随后对ordered注解的bean进行排序和注册,最后加入到BeanFactory容器中

sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

随后注册没有实现任何排序接口的的bean,加入到BeanFactory容器

registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

随后注册MergedBeanDefinitionPostProcessor类型的bean,加入到BeanFactory容器

sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

最后注册ApplicationListenerDetector监听器类型的bean,加入到BeanFactory容器

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

5完成的是beanFactory的后置处理器的扫描和注册,6完成的就是bean后置处理器的扫描和注册

7,initMessageSource方法

接下来查看这个 initMessageSource 方法,顾名思义,这个方法就是用来国际化资源的一个方法。主要是创建一些 MessageSource 的类,或者获取到xml文件中的MessageSource,最后将这个实例加入到 beanFactory中

protected void initMessageSource() {
	//获取Bean工厂,一般是DefaultListBeanFactory
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	//首先判断是否已有xml文件定义了id为messageSource的bean对象
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		//如果有,则从Bean工厂得到这个bean对象
		this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
		// Make MessageSource aware of parent MessageSource.
		//当父类Bean工厂不为空,并且这个bean对象是HierarchicalMessageSource类型
		if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
			//为HierarchicalMessageSource的实现类
			HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
			//设置父类MessageSource,此处设置内部的parent messageSource
			if (hms.getParentMessageSource() == null) {
				// Only set parent context as parent MessageSource if no parent MessageSource
				// registered already.
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Using MessageSource [" + this.messageSource + "]");
		}
	}
	else {
		DelegatingMessageSource dms = new DelegatingMessageSource();
		//给这个DelegatingMessageSource添加父类消息源
		dms.setParentMessageSource(getInternalParentMessageSource());
		this.messageSource = dms;
		//将这个messageSource实例注册到Bean工厂中
		beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
		}
	}
}

8,initApplicationEventMulticaster方法

顾名思义就是初始化一个事件发布器的方法,就是先判断这个事件发布器有没有定义,如果有定义就直接用已经定义的方法,如果没有定义那么就会new一个默认事件发布器,然后注册到容器里面

在这里插入图片描述

9,onrefresh方法

接下来继续看这个onrefresh方法,其主方法为空,也就是主要是交给子类去实现,和上面的postProcessBeanFactory 方法一样,并且通过具体的实现类发现,这些实现类主要也是和web那一块相关,也就是跟springmvc和springboot那块有关

在这里插入图片描述

10,registerListeners方法

在第八个方法中,已经完成了事件发布器的初始化以及获取,这一块逻辑也比较简单,就是判断开发者有没有自定义一些事件监听器,有的话将全部的事件监听器加入到事件发布器里面

在这里插入图片描述

11,finishBeanFactoryInitialization方法

在第一篇spring的bean的什么周期中,就是通过这个方法进入的,就是实例化一些非类加载的单例bean,方法内部会调用一个 preInstantiateSingletons 用于真正的实例化剩余的单例bean,内部就会经过一些bean的实例化、属性填充、初始化等方法,以及一些bean的后置处理器的实现,aop的初始扫描,@Autowire等注解的预卖点,aop最终产生动态代理等,底层详细的可以参考这个系列的第一篇方法

在这里插入图片描述

之前画的bean的生命周期的图片,就是通过这个方法进入的,在调用getbean的流程到bean加入到concurrentHashMap的流程都在这里面实现

在这里插入图片描述

12,finishRefresh方法

在最后的refresh方法中,最后要执行的就是这个 finishRefresh ,其主要流程如下:

  • 首先第一步就是清除上下文级别的资源缓存,比如扫描出来的一些ASM元数据
  • 注册lifecycleProcessor,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新
  • getLifecycleProcessor(),实现SmartLifecycle并且isAutoStartup自动启动的Lifecycle调用start()方法
  • 随后会注册一个发布事件的容器,将那些事件发布器和事件监听器全部注册

在这里插入图片描述## 12,finishRefresh方法

在最后的refresh方法中,最后要执行的就是这个 finishRefresh ,其主要流程如下:

  • 首先第一步就是清除上下文级别的资源缓存,比如扫描出来的一些ASM元数据
  • 注册lifecycleProcessor,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新
  • getLifecycleProcessor(),实现SmartLifecycle并且isAutoStartup自动启动的Lifecycle调用start()方法
  • 随后会注册一个发布事件的容器,将那些事件发布器和事件监听器全部注册

在这里插入图片描述