invokeBeanFactoryPostProcessors的理解

news2024/11/24 5:59:19

invokeBeanFactoryPostProcessors的理解

Spring中有两个非常重要的扩展点:

  • BeanFactoryPostProcessor
  • BeanPostProcessor
    其中第一个是可以对BeanDefinition注册时进行扩展,而第二个是对spring中IOC容器中的对象进行实例化的时候进行扩展。
    今天主要谈一下对BeanFactoryPostProcessor的几点理解:

BeanFactoryPostProcessor

  • 这是个重要的接口,其还有一个子接口:BeanDefinitionRegistryPostProcessor:
    在这里插入图片描述
  • 在spring容器的启动过程,对所有组件的注册主要就是通过对这两个接口的处理来完成的。
  • spring启动时,最主要的方法就是refresh方法:
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				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();
			}
		}
	}
  • 其中,invokeBeanFactoryPostProcessors这个方法,就是处理容器中所有bean的注册过程
  • invokeBeanFactoryPostProcessors这个方法具体如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}
  • 这个方法,其实只有第一条语句中的invokeBeanFactoryPostProcessors方法,是重要且对容器bean注册有效
  • 这个方法传入的参数第一个是工厂,第二个参数是BeanFactoryPostProcessor的list
  • 正常启动的时候,如果我们不做处理,那么第二个参数就是一个空的list
  • 我们也可以在代码中进行BeanFactoryPostProcessor的注入
  • spring容器启动到这里时,会自动注册5个bean:
    在这里插入图片描述

上述图片中:

  1. 第一个ConfigurationClassPostProcessor,实现的是BeanDefinitionRegistryPostProcessor接口,是最主要的扫描和注册
  2. 第三个EventListenerMethodProcessor,实现BeanFactoryPostProcessor接口,与事件相关的处理组件
  3. 第四个和第五个实现BeanPostProcessor接口,参与对象创建过程中的注入等处理
  • 在invokeBeanFactoryPostProcessors方法中,spring会通过所有BeanFactoryPostProcessor的功能,来扫描并注册所有的bean,从方法名称来看,其作用就是调用所有的BeanFactoryPostProcessor,

其主要处理流程如下:

  1. 对传入的BeanFactoryPostProcessor进行处理,添加进等待运行的列表中
    在这里插入图片描述
  2. 对实现了BeanDefinitionRegistryPostProcessor以及PriorityOrdered接口的组件进行实例化,并调用BeanDefinitionRegistryPostProcessor接口方法,此时,就是调用ConfigurationClassPostProcessor这个组件,来进行容器中bean的注册,具体的注册过程此处略过不表
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
  1. 对实现了BeanDefinitionRegistryPostProcessor以及Ordered接口的组件进行实例化,并调用相应接口方法
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
  1. 对只实现了BeanDefinitionRegistryPostProcessor接口的组件进行实例化,并调用相应接口方法
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}
  1. 对实现了BeanDefinitionRegistryPostProcessor的组件,调用其父接口BeanFactoryPostProcessor的方法
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
  1. 对实现了BeanFactoryPostProcessor以及PriorityOrdered接口的组件,调用相应接口中的方法
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
  1. 对实现了BeanFactoryPostProcessor以及Ordered接口的组件进行实例化,并调用相应接口方法
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
  1. 对只实现了BeanFactoryPostProcessor接口的组件进行实例化,并调用相应接口方法
// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

总结:

  • 此方法主要作用,就是按照顺序分别调用实现了BeanDefinitionRegistryPostProcessor接口的组件以及实现了BeanFactoryPostProcessor接口的组件;其中最主要的组件就是ConfigurationClassPostProcessor,其实现的是子接口,实现的方法功能,就是对容器中进行beanDefinition的注册。

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

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

相关文章

【安全漏洞】水平权限漏洞和垂直权限漏洞

前言 权限校验非常重要。如果不对水平、垂直权限做校验&#xff0c;就会发生泄漏用户数据的事故&#xff0c;造成P0故障。 一、水平权限漏洞 1、水平权限漏洞基本概念 什么是水平权限漏洞呢&#xff1f; 简单来说&#xff0c;水平权限漏洞是用户CURD了本不属于他的资源。以上图…

复活天若OCR的谷歌翻译接口

文章目录1. 资源2. 效果3. 前言4. 网络相关4.1. 网络判断4.2. 网络设置5. 修改5.1. 代码修改原理5.2. 代码修改1. 资源 这里直接放出来我已经修改编译好的天若OCR&#xff0c;开箱即用&#xff1a;https://www.lanzoui.com/ifT8t0jfv1gd 访问码&#xff1a;24647 不过需要说明…

性能优化系列之如何为不同格式的图片选择合适的应用场景?

文章の目录一、JPEG&#xff08;Joint Photographic Experts Group&#xff09;1、介绍2、不适合情形3、非常适合的情形二、PNG&#xff08;Portable Network Graphics&#xff09;1、介绍2、不适合的情形3、非常适合的情形三、GIF&#xff08;Graphics Interchange Format&…

【nowcoder】笔试强训Day9

目录 一、选择题 二、编程题 2.1另类加法 2.2走方格的方案数 一、选择题 1.下面程序的输出是:() String x"fmn"; x.toUpperCase(); String yx.replace(f,F); yy"wxy"; System.out.println(y); A FmNwxy B fmnwxy C wxyfmn D Fmnwxy String x “…

决胜「年货时代」:一场关于零食的品质突围

“都说冰糖葫芦儿酸&#xff0c;酸里面它裹着甜&#xff1b;都说冰糖葫芦儿甜&#xff0c;可甜里面它透着那酸。” 1995年春节&#xff0c;伴随着《冰糖葫芦》唱响大街小巷&#xff0c;小贩骑着自行车&#xff0c;后车座的草靶子上插满冰糖葫芦&#xff0c;或摆在集市上&#…

大数据系列——什么是hive?hive用来干什么的?hive常见问题是啥?

目录 一、什么是hive 二、为什么要使用Hive 三、Hive与Hadoop的关系 四、Hive与HDFS的关系 五、Hive与传统数据库区别 六、Hive中的数据存储是怎样的 七、对hive进行增删改查 八、排序逻辑 九、hive不支持update数据的解决方案 十、Hive中支持的分区类型有两种 十…

Linux部署前端Vue项目

Linux部署前端Vue项目 1 部署到tomcat上 1.1 部署Vue项目 打包项目 在命令行终端&#xff0c;输入命令&#xff0c;打包项目&#xff1a; npm run build将生成的dist文件夹下的所有内容复制到tomcat的webapps下 "推荐":在webapps下新建一个文件夹&#xff0c;例…

【互信息驱动:可逆神经网络】

Mutual Information-driven Pan-sharpening &#xff08;互信息驱动的全色锐化&#xff09; 全色锐化的目的是综合纹理丰富的全色图像和多光谱图像的互补信息&#xff0c;生成纹理丰富的多光谱图像。尽管已有的全色锐化方法取得了显著的进步&#xff0c;但它们并没有明确地加…

动态圣诞树-HTML

<!DOCTYPE HTML PUBLIC> <html> <head> <title>圣诞树</title> <meta charset"utf-8" > <style> html, body { width: 100%; height: 100%; margin: 0; padding: 0; border: 0; } div { margin: 0; padding: 0; border: 0…

docker高级篇:实战-自己开发的微服务怎么在docker上面运行?

通过前面的一系列学习,我们已经知道怎么制作dockerfile了。那么,本篇文章,咱们就把自己写的spring boot的demo项目,部署在docker上面。 案例目标: 我们自己开发的微服务怎么在docker上面运行呢? 1:通过IDEA新建一个普通的微服务模块 2:通过dockerfile发布微服务部署…

通过 api 和 keycloak 理解OIDC认证

参考资料 通过Keycloak API理解OAuth2与OpenID Connect 什么是keycloak如何在nodejs中使用它 如何通过 OIDC 协议实现单点登录&#xff1f; https://jwt.io/#encoded-jwt OIDC认证的简单demo 单点登录&#xff08;Single Sign On&#xff09;是目前比较流行的企业业务整合…

cut与分层抽样(Stratified Sampling)

个人觉得&#xff0c; 把分层抽样称为“分类采样”会更贴切一些。通常最基本的采样手段是&#xff1a;随机抽样&#xff0c;但是在很多场景下&#xff0c;随机抽样是有问题的&#xff0c;举一个简单的例子&#xff1a;如果现在要发起一个啤酒品牌知名度的调查问卷&#xff0c;我…

二、let进阶、const、全部变量与顶层对象

二、let进阶、const、全部变量与顶层对象 一、let进阶 let创建了块级作用域&#xff0c;每次循环时内部的块级作用域都会去访问外层块级作用域中的变量i&#xff0c;而外层块级作用域中的变量i都不同&#xff0c;所以打印0-9&#xff1b;类似于闭包&#xff1a;内部函数返回到…

MySQL【Primary key】主键约束

关键字: [ primary key ] 作用&#xff1a;用来唯一标识表中的一行记录 特点&#xff1a;1.唯一性约束非空约束 唯一且为空 唯一性约束&#xff1a;不允许出现重复值 非空约束&#xff1a;不允许出现空值&#xff0c;但不是 NULL 2.一个表最多只能有一个主键约束&#x…

35岁之后软件测试工程师靠什么养家?我还能继续做测试。

35岁真是一个焦虑的年龄&#xff0c;我一个在北京软件测试的朋友从一个大公司裸辞以后&#xff0c;年前应聘到了一家小公司做技术总监&#xff0c;因为疫情的爆发&#xff0c;公司倒闭了&#xff0c;他失业了。为了养家我这个朋友不得不冒着被病毒感染的危险开始送外卖。作为一…

Springboot整合Liquibase初始化数据库

一、前言 liquibase是一个数据库变更的版本控制工具。项目中通过liquibase解析用户编写的liquibase的配置文件,生成sql语句&#xff0c;并执行和记录。执行是根据记录确定sql语句是否曾经执行过&#xff0c;和配置文件里的预判断语句确定sql是否执行。 本篇文章给大家介绍spr…

RabbitMQ浏览器UI插件

Awesome RabbitMQ Management 该插件中文意思是"很棒的 RabbitMQ 管理",是对原生RabbitMQ的UI图形界面进行增强的一款插件。 可在Google Chrome商店中下载安装 概述 原文介绍 Awesome RabbitMQ Management RabbitMQ queues view can become unusable with many qu…

微服务 Spring Boot Mybatis-Plus 整合 EasyPOI 实现 Excel 一对多 导入

文章目录⛄引言一、EasyPOI 实现Excel 的一对多导入 -- 代码实现⛅需求说明⚡核心源码实现二、Easy POI 实现一对多导入 -- 测试三、效果图展示⛵小结⛄引言 Excel导入 是 开发中 很常用的 功能 &#xff0c;本篇讲解 如何使用 Spring Boot MyBatis -Plus 整合 EasyPOI 实现E…

2023年淘宝天猫年货节超级红包哪里领?

2023年淘宝天猫年货节超级红包哪里领? 姐妹们在淘宝年货节活动就就就要开始预热模式了&#xff0c;时间是12月27日中午12点&#xff0c;大家最爱的项目一定是领取超级红包了。这不&#xff0c;2023年的年货节就要开启了。但是&#xff0c;很多小伙伴还不知道&#xff0c;淘宝…

<生产者、消费者问题>——《Linux》

目录 1. 生产者消费者模型 1.1 为何要使用生产者消费者模型 1.2 生产者消费者模型优点 2.基于BlockingQueue的生产者消费者模型 2.1 BlockingQueue 2.2 C queue模拟阻塞队列的生产消费模型 3.POSIX信号量 4.基于环形队列的生产消费模型 后记&#xff1a;●由于作者水平…