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

devtools/2024/11/29 17:43:32/

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/devtools/137981.html

相关文章

C#基础题

用C#控制台程序来实现&#xff0c;从键盘输入5个整数&#xff0c;输出其中最大数 输入5个数我们为了方便&#xff0c;可以进行循环&#xff0c;代码如下&#xff1a; int max int.MinValue; for (int i 0; i < 5; i) { Console.WriteLine("请输入第 {0} 个整数:…

不需要双手离开键盘 vscode

目标是“不需要双手离开键盘”&#xff01; ctrl shift O 打开函数导航窗格 ctrl enter 行中换行 alt ↑/↓上下移行 shift alt ↑/↓上下复制 ctrl ←/→ 按代码块移动 ctrl delete / backspace按代码块删除 ctrl l 选择单行 shift delete 删除整行 ctrl C/V 复制/…

docker compose 使用记录

作用 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。通过一个 YAML 文件来配置应用程序的服务&#xff0c;然后使用一个命令即可创建并启动所有服务。 文档位置 Part 7: Use Docker Compose | Docker Docs 使用方法 1. 安装 Docker Compose sudo curl -…

结构型模式-外观模式

外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;用于为复杂子系统提供一个统一的、高层次的接口。通过外观模式&#xff0c;客户端无需深入了解子系统的内部复杂性&#xff0c;只需与外观类交互即可完成任务&#xff0c;从而简化了使用方式&a…

神经网络中的损失函数(Loss Function)

损失函数&#xff08;Loss Function&#xff09;在机器学习和深度学习中扮演着至关重要的角色&#xff0c;它是衡量模型预测值与实际值之间差异程度的函数。通过最小化损失函数&#xff0c;我们可以优化模型的参数&#xff0c;使其预测结果更加准确。 一、损失函数的定义 损失函…

QT QFormLayout控件 全面详解

本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…

Flutter:启动屏逻辑处理02:启动页

启动屏启动之后&#xff0c;制作一个启动页面 新建splash&#xff1a;view 视图中只有一张图片sliding.png就是我们的启动图 import package:flutter/material.dart; import package:get/get.dart; import index.dart; class SplashPage extends GetView<SplashController…

Python入门(18)--实战项目

机器学习实战项目指南 &#x1f916; 项目概览 &#x1f310; 本项目是一个综合性的机器学习入门实战指南&#xff0c;通过实际案例展示机器学习项目的完整生命周期&#xff0c;包括数据处理、模型训练、评估和部署等关键环节。 1. 系统架构 &#x1f3d7;️ 1.1 核心组件 …