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

server/2024/11/30 5:08:25/

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

深入理解spring的依赖注入和属性填充

  • 一,spring中refresh刷新机制
    • 1,prepareRefresh方法
    • 2,obtainFreshBeanFactory方法
    • 3,prepareBeanFactory方法
    • 4,postProcessBeanFactory方法
    • 5,invokeBeanFactoryPostProcessors方法
    • 6,registerBeanPostProcessors方法
    • 7,initMessageSource方法
    • 8,initApplicationEventMulticaster方法
    • 9,onrefresh方法
    • 10,registerListeners方法
    • 11,finishBeanFactoryInitialization方法
    • 12,finishRefresh方法

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

springrefresh_13">一,spring中refresh刷新机制

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

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

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

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

java">@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方法用于验证环境中是否有某些属性,用来校验我们容器启动必须依赖的环境变量的值
  • 最后一步就是初始化一些监听器,以及一些早期的事件等
java">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接口回调
java">//设置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的后置处理器中,增加一个监听探测器

java">beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

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

java">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类调用实现

java">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 实现类,最后就是没有实现优先级接口的实现类

java">//获取容器中所有的 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的名称

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

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

在这里插入图片描述

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

java">sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

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

java">sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

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

java">registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

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

java">sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

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

java">beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

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

7,initMessageSource方法

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

java">protected void initMessageSource() {//获取Bean工厂,一般是DefaultListBeanFactoryConfigurableListableBeanFactory 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 messageSourceif (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()方法
  • 随后会注册一个发布事件的容器,将那些事件发布器和事件监听器全部注册

在这里插入图片描述


http://www.ppmy.cn/server/146078.html

相关文章

dmdba用户资源限制ulimit -a 部分配置未生效

dmdba用户资源限制ulimit -a 部分配置未生效 1 环境介绍2 数据库实例日志报错2.1 mpp01 实例日志报错2.2 mpp02 实例日志报错 3 mpp02 服务器资源限制情况4 关闭SELinux 问题解决4.1 临时关闭 SELinux4.2 永久关闭 SELinux 5 达梦数据库学习使用列表 1 环境介绍 Cpu x86 Os Ce…

【经典论文阅读】Transformer(多头注意力 编码器-解码器)

Transformer attention is all you need 摘要 完全舍弃循环 recurrence 和卷积 convolutions 只依赖于attention mechanisms 【1】Introduction 完全通过注意力机制&#xff0c;draw global dependencies between input and output 【2】Background 1&#xff1a;self-…

【docker集群应用】Docker数据管理与镜像创建

文章目录 Docker数据管理数据卷&#xff08;Data Volumes&#xff09;示例 数据卷容器&#xff08;Data Volume Containers&#xff09;示例 端口映射容器互联 Docker镜像的创建方法基于现有镜像创建1.首先启动一个镜像&#xff0c;在容器里做修改2.然后将修改后的容器提交为新…

Javaweb关于web.xml的相关配置信息

Javaweb关于web.xml的相关配置信息 初始页面 <!-- 规定加载进入的初始页面--> <welcome-file-list><welcome-file>/login.jsp</welcome-file> </welcome-file-list>配置Servlet <!--配置Servlet--> <servlet><servlet-name&g…

Leetcode 颠倒二进制位

以下是对所提供的代码进行中文解释以及其算法思想分析&#xff1a; 算法思想 这段代码的目标是反转一个32位整数的二进制位。 核心思路是&#xff1a; 逐位提取&#xff1a; 利用位操作从输入整数的最低位开始&#xff0c;逐位提取其二进制位。逐位插入&#xff1a; 将提取到…

深度学习作业九 RNN-SRN-Seq2Seq

目录 1. 实现SRN &#xff08;1&#xff09;使用Numpy &#xff08;2&#xff09;在1的基础上&#xff0c;增加激活函数tanh &#xff08;3&#xff09;使用nn.RNNCell实现 &#xff08;4&#xff09;使用nn.RNN实现 2. 实现“序列到序列” 3. “编码器-解码器”的简单实…

计算机网络:网络安全

7.1、网络安全概述 1、安全包括哪些方面 数据存储安全应用程序安全操作系统安全网络安全物理安全用户安全教育 2、网络安全面临的问题 1&#xff09;截获——从网络上窃听他人的通信内容。 2&#xff09;中断——有意中断他人在网络上的通信。 3&#xff09;篡改——故意…

通过优化html的清洗来提高对网页RAG的效果

html检索的提升&#xff1a;HtmlRAG 之前在现实的工作场景中也做过很多次RAG&#xff0c;不过那会我的做法大多数是对数据进行结构化&#xff0c;例如做成json或者yaml文件存放进数据库里面。比如我现在有一个Word文档需要处理&#xff0c;那我就会按照一级标题&#xff0c;二…