Spring源码之refresh

news2024/11/15 23:38:07

1.refesh的核心介绍

在 Spring 框架中,refresh 主要用于刷新应用上下文。这一过程涉及多个重要的步骤,确保 Spring 容器的状态更新、bean 的加载以及资源的初始化。

refresh 方法的主要功能

  1. 初始化上下文

    refresh 方法会初始化应用上下文,加载和配置所有的 bean,包括从配置文件、注解、XML 等中定义的 bean。
  2. 注册后处理器

    在刷新过程中,Spring 会注册各种后处理器(如 BeanPostProcessor 和 BeanFactoryPostProcessor),这些后处理器可以对 bean 的创建过程进行干预。
  3. 执行初始化逻辑

    对于那些标记了 @PostConstruct 或实现了 InitializingBean 接口的 bean,Spring 会在此阶段调用它们的初始化方法。
  4. 创建和注册 bean

    在刷新过程中,Spring 会创建所有单例 bean 的实例并将其注册到应用上下文中。这包括处理依赖注入和自动装配。
  5. 处理生命周期事件

    在上下文刷新期间,Spring 会触发相应的生命周期事件,如 ContextRefreshedEvent,让其他组件可以监听这些事件并执行特定操作。

2.register源码

处理 bean 的定义、作用域、注解等信息,并将其注册到 Spring 的 bean 注册表中。AnnotatedBeanDefinitionReader#doRegisterBean()

3.refresh源码

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 这里会判断能否刷新,并且返回一个BeanFactory, 刷新不代表完全情况,主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 准备BeanFactory
			// 1. 设置BeanFactory的类加载器、SpringEL表达式解析器、类型转化注册器
			// 2. 添加三个BeanPostProcessor,注意是 具体的BeanPostProcessor实例对象
			// 3. 记录ignoreDependencyInterface
			// 4. 记录ResolvableDependency
			// 5. 添加三个单例Bean
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 子类来设置一下BeanFactory
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				// Invoke factory processors registered as beans in the context.
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  // scanner.scan()

				// Register bean processors that intercept bean creation.
				// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				// Initialize message source for this context.
				// 设置ApplicationContext的MessageSource,要么是用户设置的,要么是DelegatingMessageSource
				initMessageSource();

				// Initialize event multicaster for this context.
				// 设置ApplicationContext的applicationEventMulticaster,要么是用户设置的,要么是SimpleApplicationEventMulticaster
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 给子类的模板方法
				onRefresh();

				// Check for listener beans and register them.
				// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				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.
				destroyBeans();

				// Reset 'active' flag.
				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...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

3.1.首先是prepareRefresh方法

1.1initPropertySources模板方法,留给子类重写,

1.2validateRequiredProperties,从Environment中拿出key-value,包含系统环境变量和jvm环境变量,这个函数来验证目前需要使用到的key是否存在,如果不存在则报出异常。

说明:validateRequiredProperties 方法的主要作用是验证一组必需属性是否已被正确设置。通过抛出异常,它可以有效地提醒开发者或运维人员缺失的配置,从而提高应用的健壮性和可靠性。

1.3设置成员属性,主要是监听器。

// Initialize any placeholder property sources in the context environment.
		// 比如子类可以把ServletContext中的参数对设置到Environment
		// 模板方法
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

3.2obtainFreshBeanFactory

这里会判断能否刷新,并且返回一个BeanFactory,刷新不代表完全情况。主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等。

对于SpringBoot,使用容器是AnnotationConfigApplicationContext,不能重复刷新;

对于SpringMVC,使用的是AnnotationConfigWebApplicationContext,可以重复刷新;

并且,这两个容器的初始化时机不同,SpringBoot在this中初始化容器,而SpringMVC是在刷新的时候进行初始化。

3.3prepareBeanFactory--准备BeanFactory

// Spring5.3中新增的功能,可以选择是否开启Spel功能,shouldIgnoreSpel默认为false,表示开启
		if (!shouldIgnoreSpel) {	//  @Value(#{xxx})的解析器
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}

		// 添加一个ResourceEditorRegistrar,注册一些级别的 类型转化器
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		// 组成一个BeanPostProcessor,用来处理EnvironmentAware、EmbeddedValueResolverAware等回调
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

3.1拿到BeanClassLoader,我们可以自己给Bean工厂设置类加载器

3.2设置SpringEL的解析器,#{XXX}

3.3设置类型转换器ResourceEditorRegistrar,里面有很多转换器,比如Spring字符串-->File文件

3.4添加ApplicationContextAwareProcessor到BeanPostProcessor中,处理Aware的回调,它已经添加到BeanPostProcessor的list当中

比如,一个方法实现了Aware接口,那么在创建完bean的时候,就会调用方法中重写了接口的方法。

3.5ignoreDependencyInterface

将需要忽略的放入集合当中,在自动注入(依赖注入)的时候,如果类实现了这些接口,那么依赖注入就不会调用set方法执行,而只在最后执行一次set方法

3.6registerResolvableDependency

将这些东西直接注册为bean,类型对应

3.7添加ApplicationListenerDetector,它已经添加到BeanPostProcessor的list当中

这是监听器的BeanPostProcessor。

3.8判断是否有这些和环境变量相关的Bean。如果没有,那就给你添加bean到BeanFactory

包含系统环境变量、JVM环境变量、监控的对象。

3.4postProcessBeanFactory

这是一个模板方法

3.5.invokeBeanFactoryPostProcessors(内容很多,后面再讲)

扫描类,生成BeanDefinition,然后将BeanDefinition放到BeanFactory中

在执行这个方法之前,只是生成了BeanFactory容器自己需要用到的BeanDefinition,但是用户定义的类的BeanDefinition还没有生成,比如userService和orderService。

3.6.registerBeanPostProcessors

将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去,在Bean创建的时候会用beanPostProcessors。

3.7.initMessageSource

国际化

如果我们定义了messageSource名字的Bean,在这里就会将它设置为项目的国际化,否则使用spring默认的国际化工具。

3.8.initApplicationEventMulticaster

注册事件发布器,进行事件的发布。

如果程序员定义了那就用定义的,否则就用默认生成的发布器SimpleApplicationEventMulticaster

3.9.onRefresh

模板方法

3.10.registerListeners

注册监听器,将程序员定义好的监听器存储起来,设置到发布器的属性中去。

3.11.finishBeanFactoryInitialization,完成bean工厂的初始化!

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		// 如果BeanFactory中存在名字叫conversionService的Bean,则设置为BeanFactory的conversionService属性
		// ConversionService是用来进行类型转化的
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no BeanFactoryPostProcessor
		// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		// 设置默认的占位符解析器  ${xxx}  ---key
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 实例化非懒加载的单例Bean
		beanFactory.preInstantiateSingletons();
	}

3.11.1ConversionService

设置一些类型转换器的Bean

3.11.2设置默认的占位符解析器,${XXX},解析Environment的key-value

3.11.3 preInstantiateSingletons,实例化非懒加载的单例Bean,bean生命周期的入口!!!重点!!后面会详细讲!

3.12.finishRefresh

3.12.1initLifecycleProcessor();

和Spring容器的生命周期有关。我们可以实现smartLiftcycle接口,然后重写start,stop,running方法,检测Spring容器的生命周期。

3.12.2publishEvent

发布 容器启动完成的事件

4.invokeBeanFactoryPostProcessors

作用:生成BeanDefinition,将BeanDefinition注册到bean工厂中,其中包括相关配置类、userService(程序员自己定义的)等全部定义的bean。

核心方法是invokeBeanFactoryPostProcessors,其中一个入参为List<BeanFactoryPostProcessor> beanFactoryPostProcessors,它主要包含两个部分:BeanFactoryPostProcessor(后执行)和BeanDefinitionRegistryPostProcessor(先执行)(可以注册新的beanDefinition)

postProcessBeanDefinitionRegistry:可以注册新的beanDefinition,创建beanDefinition;

postProcessBeanFactory:只能修改beanDefinition,增强beanDefinition;

postProcessBeanDefinitionRegistry继承postProcessBeanFactory!

1.1先执行通过ApplicationContext.add添加进来的BeanDefinitionRegistryPostProcessor 的

postProcessBeanDefinitionRegistry()方法。

这个方法中有个重要的方法processConfigBeanDefinitions,它会解析定义的配置类,生成所有BeanDefinition

// beanFactoryPostProcessors集合一般情况下 都是空的,除非我们手动调用容器的addBeanFactoryPostProcessor方法添加了
			// beanFactoryPostProcessors中可能包含了:普通BeanFactoryPostProcessor对象和BeanDefinitionRegistryPostProcessor对象
			// 对于BeanDefinitionRegistryPostProcessor对象,会执行自己的postProcessBeanDefinitionRegistry()方法
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);// 先执行postProcessBeanDefinitionRegistry方法
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

1.2 getBeanNamesForType

拿到的类型是BeanDefinitionRegistryPostProcessor

先将拿到的ConfigurationClassPostProcessor(配置类的PostProcessor)加入list

1.3核心:然后按顺序,顺序为实现了PriorityOrdered接口、Ordered接口、自定义的PostProcessor的postProcessBeanDefinitionRegistry()方法。(按顺序去将实现了PriorityOrdered、Ordered接口的类,生成BeanDefinition

1.4核心:然后开始执行postProcessBeanFactory,也是按顺序执行,依次执行子接口的方法、实现了PriorityOrdered接口、Ordered接口、自定义的PostProcessor的postProcessBeanFactory()方法。(增强BeanDefinition,修改属性

使用:我们可以自定义实现BeanFactoryPostProcessor接口或者它的子类BeanDefinitionRegistryPostProcessor,重写他们的方法。子类可以新增BeanDefinition,父类可以增强或者修改BeanDefinition的一些属性

5.registerBeanPostProcessors

作用:将扫描到的BeanPostProcessors实例化并排序,添加到BeanFactory的beanPostProcessors属性中去。(添加BeanPostProcessor到BeanPostProcessors中,创建bean的时候使用它)

循环、排序、加到beanPostProcessors的list中!

1.getBeanNamesForType

首先,拿到BeanPostProcessors类型的Bean(也就是拿到所有的BeanPostProcessor)

2.分类

根据实现的接口类型,进行分类。(PriorityOrdered、Ordered、其他)

3.排序

根据实现的接口类型,进行排序。(PriorityOrdered、Ordered、其他)

4.添加到list当中(其中实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor放到list的最后面,意思可能是用户定义的先放(用户的优先级较高),然后存放容器提供的)

list指的是存放BeanPostProcessor(后置处理器)的集合,在创建Bean的时候,会经常用到这个list。

private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目实战】智能机械臂协同视觉辅助仓储物流管控平台

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

9月4日星期三今日早报简报微语报早读

9月4日星期三&#xff0c;农历八月初二&#xff0c;早报微语早读。 1、全球第二批100个地质遗产地公布&#xff0c;中国乌海、自贡、桂林等3地入选&#xff1b; 2、我国科学家在超高纯石墨领域取得重大突破&#xff1b; 3、2024上海百强企业榜单发布&#xff1a;入围门槛105…

小土堆pytorch

anaconda安装 pip list 可以看有哪些package包 nvidia-smi查看显卡的状态 安装pytorch 检验pytorch是否安装成功&#xff0c;以及是否pytorch是否可以使用gpu。 (1)查看conda版本 conda --version 或 conda -V (2)更新conda&#xff08;将conda自身更新到最新版本&#xff09; …

算法打卡 Day28(回溯算法)-组合总数 + 组合总数 Ⅱ+ 电话号码的字母组合

文章目录 Leetcode 17-电话号码的字母组合题目描述解题思路 Leetcode 39-组合总数题目描述解题思路 Leetcode 216-组合总数 Ⅲ题目描述解题思路 Leetcode 17-电话号码的字母组合 题目描述 https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/ …

Flink问题记录

尚硅谷Flink1.17问题记录 上手pom依赖循环递归WordCountStreamDemo中readTextFile是deprecated&#xff08;强烈反对的&#xff09; 上手 pom依赖循环递归 pom依赖中&#xff1a; <dependency><groupId>org.apache.flink</groupId><artifactId>flink…

J.U.C Review - 线程池原理/源码解析

文章目录 为什么要使用线程池ThreadPoolExecutor构造方法解析常见的阻塞队列实现及其特性阻塞队列在实际应用中的适用场景分析自定义ThreadFactory和RejectedExecutionHandler实际使用中的示例与代码片段 线程池的状态线程池的任务处理流程线程复用的实现四种常见的线程池newCa…

uniapp 自定义微信小程序 tabBar 导航栏

背景 做了一个校园招聘类小程序&#xff0c;使用 uniapp vue3 uview-plus pinia 构建&#xff0c;这个小程序要实现多角色登录&#xff0c;根据权限动态切换 tab 栏文字、图标。 使用pages.json中配置tabBar无法根据角色动态配置 tabBar&#xff0c;因此自定义tabBar&…

达梦数据库的系统视图v$ifun

达梦数据库的系统视图v$ifun 达梦数据库&#xff08;DM Database&#xff09;中V$IFUN 视图是用于检测函&#xff08;Function&#xff09;信息的。 在 Oracle 数据库中&#xff0c;类似的系统视图被称为动态性能视图&#xff0c;但在达梦数据库中并没有与 Oracle 一一对应的…

QT(1)-.pro 文件 转成.vcxproj 工程

1.qtcreator创建的文件转换成vs2019可以打开的。 1.QT webenginewidgets unknown modules webenginewidgets 要用 MSVC2017 &#xff0c;用minGW 32构建

使用Django身份验证系统

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) Django 5框…

windows中Selenium安装最新版Chrome WebDriver

windows中Selenium安装最新版Chrome WebDriver 需求&#xff1a;需要使用 selenium 对某个网页进行截图 文章目录 windows中Selenium安装最新版Chrome WebDriver一、查看Chrome版本二、找到对应的chromedriver版本三 安装3.1 确定google安装路径3.2 将下载的google driver 解压…

解决bug: RuntimeError: Address already in use,一个linux下pytorch多卡训练tcp端口占用的bug

时间&#xff1a;2024.9.3 1&#xff09;bug&#xff1a; self._store TCPStore( # type: ignore[call-arg] RuntimeError: Address already in use2&#xff09;原因分析 linux下pytorch多卡训练深度学习模型&#xff0c;训练中途暂停训练&#xff0c;但仍有进程占用某个端…

字典树Trie(专项复习)

一.P8306 【模板】字典树 题目思路:字典树的板子题,熟练写出insert函数(建树),以及query函数(查询)即可. 代码实现: #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; typedef long long ll; #define N 3000005 #define P 131 ll f1[N]; s…

华为云征文|Flexus云服务X实例安装ODBC驱动,在ODBC中建立MySQL数据库连接,通过QT连接云数据库

引出 4核12G-100G-3M规格的Flexus X实例使用测评第2弹&#xff1a;Flexus云服务X实例安装ODBC驱动&#xff0c;在ODBC中建立MySQL数据库连接&#xff0c;通过QT连接云数据库 什么是Flexus云服务器X实例 官方解释&#xff1a; Flexus云服务器X实例是新一代面向中小企业和开发…

第140天:内网安全-横向移动局域网ARP欺骗DNS劫持钓鱼中间人单双向

目录 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 案例二&#xff1a;局域网&工作组-ARP欺骗-劫持数据-双向 案例三&#xff1a;局域网&工作组-DNS 劫持-钓鱼渗透-双向 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 原理&#xff1…

pytorch利用简单CNN实现葡萄病虫害图片识别

1 前言 之前我开发了一个葡萄病虫害的可视化系统&#xff0c;最近就想给这个系统增加2个功能&#xff0c;一个是对接一个AI助手&#xff0c;可以进行葡萄病虫害的咨询&#xff0c;直接对接千问大模型&#xff0c;这个在之前的博文里已经介绍过对接方法了&#xff0c;第二个是做…

ChatGPT与R语言融合技术在生态环境数据统计分析、绘图、模型中的实践与进阶应用

自2022年GPT&#xff08;Generative Pre-trained Transformer&#xff09;大语言模型的发布以来&#xff0c;它以其卓越的自然语言处理能力和广泛的应用潜力&#xff0c;在学术界和工业界掀起了一场革命。在短短一年多的时间里&#xff0c;GPT已经在多个领域展现出其独特的价值…

【JavaWeb】JDBCDruidTomcat入门使用

本章使用技术版本&#xff1a; Tomcatv10.1.25 关于javaweb相关的其他技术&#xff0c;比如tomcat和maven&#xff0c;在我的主页记录了笔记&#xff0c;ajax我用的是本地笔记以后再考虑上传&#xff0c;前端三板斧我用的菜鸟教程文档 JDBC 初识 JDBC概念 JDBC 就是使用Jav…

MatLab基础学习01

MatLab基础学习01 1.基础入门2.MatLab的数据类型2.1数字2.2字符串2.3矩阵2.4.元胞数组2.5结构体 3.MatLab的矩阵的操作3.1矩阵定义与构造3.2矩阵的下标取值 4.MatLab的逻辑流程4. For循环结构4.2 While循环&#xff0c;当条件成立的时候进行循环4.3 IF end 1.基础入门 matlba必…

1.3 SQL注入之MYSQL系统库

一.系统库释义 提供了访问数据库元数据的方式 元数据是关于数据库的数据&#xff0c;如数据库名和表名&#xff0c;列的数据类型或访问权限。 1.information_schema 库&#xff1a;是信息数据库&#xff0c;其中保存着关于MySQL服务器所维护的所有其他数据库的信息&#xff1…