Sping源码(八)—registerBeanPostProcessors

序言

之前我们用大量的篇幅介绍过invokeBeanFactoryPostProcessors()方法的执行流程。
invokeBeanFactoryPostProcessors的主要逻辑就是遍历执行实现了BeanDefinitionRegistryPostProcesso类(主要是针对BeanDefinition的操作)和BeanFactoryPostProcessor(主要针对BeanFacroty的操作)
我们这篇文章里要介绍的registerBeanPostProcessors()方法 和 invokeBeanFactoryPostProcessors()方法类似,作用对象是Bean,用于在 Spring 容器实例化、配置和初始化 bean 的过程中提供自定义的扩展点。

源码

获取系统中实现BeanPostProcessor的类并进行分类,添加到BeanFacroty中。处理逻辑和BeanPosrProcessor基本相似。

	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		//获取所有实现了BeanPostProcessor类的BeanName
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.

		//这里的 +1,应该是为了为下方的 new BeanPostProcessorChecker 留个位置
		//创建的BeanPostProcessorChecker是用来
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.

		//用来存放实现riorityOrdered的BeanPostProcessor
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		//用来存放实现MergedBeanDefinitionPostProcessor的BeanPostProcessor
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		//用来存放实现Ordered的BeanPostProcessor
		List<String> orderedPostProcessorNames = new ArrayList<>();
		//用来存放没有实现排序接口的BeanPostProcessor
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();

		//遍历获取所有的BeanPostProcessor
		for (String ppName : postProcessorNames) {
			//判断是否实现了PriorityOrdered接口
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				//获取BeanPostProcessor
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				//判断是否实现了MergedBeanDefinitionPostProcessor接口
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			//如果实现了Ordered接口,则添加到orderedPostProcessorNames中
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				//否则就是没有实现排序接口的类
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.

		//根据优先级进行排序
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		//注册(循环添加到BeanFactory的beanPostProcessors集合中)实现priorityOrder接口的BeanPostProcessor
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.

		//注册(循环添加到BeanFactory的beanPostProcessors集合中)实现Ordered接口的BeanPostProcessor
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		//最后注册(循环添加到BeanFactory的beanPostProcessors集合中)没有实现排序接口的BeanPostProcessor
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.

		//重新注册(循环添加到BeanFactory的beanPostProcessors集合中)实现MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).

		//注册ApplicationListenerDetector,
		// 其实refresh()主流程方法下的prepareBeanFactory(beanFactory)方法中已经向beanFactory中添加了ApplicationListenerDetector
		//这里是重新注册,保证ApplicationListenerDetector在beanPostProcessors集合的最后
		//目的是检测并管理应用程序上下文中的事件监听器。
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

扩展

值得说的地方是Spirng提供了几个比较重要的BeanPostProcessor接口可以用来进行扩展。因为其与四个接口都继承自BeanPostProcessor所以BeanPostProcessor中的方法他们也都有。
在这里插入图片描述
挨个接口来看看里面都有什么。

BeanPostProcessor
bean的后置处理器接口,在依赖注入的初始化方法前后进行调用。

/**
 * bean的后置处理器接口,在依赖注入的初始化方法前后进行调用
 */
public interface BeanPostProcessor {

	/**
	 * 初始化方法调用前要进行的处理逻辑
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 在初始化方法指定后要进行的处理逻辑
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

InstantiationAwareBeanPostProcessor
新增了属性注入的方法。

/**
 * 继承自BeanPostProcessor,添加了实例化前,实例化后,属性注入后的处理方法
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	//省略BeanPostProcessor方法...

	/**
	 * 当使用注解的时候,通过这个方法来完成属性的注入
	 */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 属性注入后执行的方法,在5.1版本被废弃
	 */
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

}

SmartInstantiationAwareBeanPostProcessor
继承自InstantiationAwareBeanPostProcessor ,额外增加3个方法。

/**
 * 继承自InstantiationAwareBeanPostProcessor接口,增加了三个额外处理的方法,由spring内部使用
 *
 */
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	/**
	 * 预测bean的类型,主要是在bean还没有创建前我们需要获取bean的类型
	 *
	 */
	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 完成对构造函数的解析和推断
	 */
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 解决循环依赖问题,通过此方法提前暴露一个合格的对象
	 *
	 */
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

MergedBeanDefinitionPostProcessor
两个BeanDefinition合并时调用。

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	/**
	 *spring通过此方法找出所有需要注入的字段,同时做缓存
	 */
	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	/**
	 * 用于在BeanDefinition被修改后,清除容器的缓存
	 */
	default void resetBeanDefinition(String beanName) {
	}
}

DestructionAwareBeanPostProcessor
判断Bean是否应该销毁和销毁时调用

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

	/**
	 * 在bean被销毁前调用
	 */
	void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

	/**
	 * 判断是否要进行销毁,一般情况下都需要
	 */
	default boolean requiresDestruction(Object bean) {
		return true;
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring-boot集成slf4j(二)logback配置详解

一、configuration 根节点&#xff1a;configuration&#xff0c;作为顶级标签&#xff0c; 可以用来配置一些lockback的全局属性&#xff0c;常见的属性如下&#xff1a; &#xff08;1&#xff09;scan“true” &#xff1a;scan是否开启自动扫描&#xff0c;监控配置文件更…

XShell-连接-Centos 7

XShell 连接Centos 7 一.准备 安装XShell XShell下载地址&#xff1a; 在虚拟机上安装Centos 7&#xff0c;具体操作自行学习 二.Centos 7的准备 1.网络适配器修改为NAT 2.获取IP 输入命令&#xff1a; ip addr我的Centos 7对外IP为192.168.174.129 三.XShell连接Cento…

Big Demo Day第十三期活动即将启幕,Web3创新项目精彩纷呈,PEPE大奖等你抽取

5月28号在香港数码港 Big Demo Day第十三期 活动即将拉开帷幕&#xff0c;活动将汇集众多Web3领域的创新项目&#xff0c;为参会者带来一场科技与智慧交融的盛宴。在这里&#xff0c;你不仅能深入了解区块链、AI等前沿技术的最新应用&#xff0c;还能有机会赢取丰厚的PEPE大奖。…

使用maven-helper插件解决jar包冲突

发现问题 maven-helper分析问题 如上所述&#xff0c;问题就是依赖版本冲突了&#xff0c;出现版本冲突的原因是因为由于Maven具有依赖传递性&#xff0c;所以当你引入一个依赖类的同时&#xff0c;其身后的依赖类也一起如过江之鲫纷至沓来了。 举个例子&#xff1a;   A依赖…

保护元件-详实的熔断器(保险丝)知识

目录&#xff1a; 一、汽车保险丝设计与选型 1、概述 2、构造及工作原理 1&#xff09;构造 2&#xff09;工作原理 3&#xff09;保险丝熔断及分断时间 4&#xff09;时间/电流特性曲线 5&#xff09;环境温度修正系数 3、熔化热能值I2t★ 4、三种电流模型 1&a…

废物回收机构|基于SprinBoot+vue的地方废物回收机构管理系统(源码+数据库+文档)

地方废物回收机构管理系统 目录 基于SprinBootvue的地方废物回收机构管理系统 一、前言 二、系统设计 三、系统功能设计 1管理员功能模块 2 员工功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍…

瑞芯微RV1126——人脸识别框架分析

项目核心是在Linux平台上利用摄像头采集人脸&#xff0c;并进行人脸识别。这个项目使用的是FFMPEGOPENCV虹软框架完成。 FFMPEG的主要工作是负责采集摄像头的数据并把摄像头数据发送给opencv。 Opencv的主要工作则是把摄像头数据转换成矩阵数据。 虹软的主要功能则是利用Open…

K8s 二进制部署---下篇(多master节点 负载均衡 高可用)

一 master02 节点部署 master01192.168.11.5kube-apiserver&#xff0c;kube-controller-manager&#xff0c;kube-scheduler&#xff0c;etcdmaster02192.168.11.12kube-apiserver&#xff0c;kube-controller-manager&#xff0c;kube-scheduler&#xff0c;etcdnode01192.1…

WebGL渲染引擎优化方向——渲染帧率的优化

作者&#xff1a;caven chen 对此内容感兴趣还可以看前文&#xff1a; WebGL渲染引擎优化方向——加载性能优化 前言 WebGL 是一种强大的图形渲染技术&#xff0c;可以在浏览器中快速渲染复杂的 3D 场景。但是&#xff0c;由于 WebGL 的高性能和高质量要求&#xff0c;如果…

白嫖免费图床!CloudFlare R2太香了!

1 为啥要折腾搭建一个专属图床&#xff1f; 技术大佬写博客都用 md 格式&#xff0c;要在多平台发布&#xff0c;图片就得有外链后续如博客迁移&#xff0c;国内博客网站如掘金&#xff0c;简书&#xff0c;语雀等都做了防盗链&#xff0c;图片无法迁移 2 为啥选择CloudFlare…

记录一个写SpringBoot中Hive数据可以正常提取但无法存到MySQL的bug

【背景】 我正在用SpringBoot框架写一个数据治理项目&#xff0c;目前所处阶段是将hive和hdfs中的元数据提取出来&#xff0c;存储到MySQL中&#xff0c;我的hive和hdfs上的数据存储在三台Linux服务器上&#xff08;hadoop102-104&#xff09;&#xff0c;MySQL在我本地Window…

运行vue2项目基本过程

目录 步骤1 步骤2 步骤3 补充&#xff1a; 解决方法&#xff1a; node-scss安装失败解决办法 步骤1 安装npm 步骤2 切换淘宝镜像 #最新地址 淘宝 NPM 镜像站喊你切换新域名啦! npm config set registry https://registry.npmmirror.com 步骤3 安装vue-cli npm install…

【Python进阶】主流电商平台数据分析||数据采集返回商品详情主题链接主图SKU数据

Python是一种高级编程语言&#xff0c;广泛应用于软件开发、数据分析、人工智能、科学计算等领域。在软件开发方面&#xff0c;Python在网站开发、网络编程、桌面软件开发等方面有着广泛的应用。在数据分析和人工智能领域&#xff0c;Python的各种库如NumPy、Pandas、Matplotli…

小程序开发的基本用法

一:基本组件 1.view和scroll-view view等同于div,view写在小程序显示和div一样的效果. srcoll-view scroll-x/scroll-y是div能移动的.但是小程序没有显示大的划的. 且scroll-view才能实现这个,要这个组件且要属性,内部基本结构才能实现. view没有属性实现. 2.swiper和swi…

温故而知新-秒杀项目篇【面试复习】

温故而知新-秒杀项目篇【面试复习】 前言版权推荐温故而知新-论坛项目篇【面试】秒杀项目中注册模块怎么实现的&#xff1f;秒杀项目中登录模块怎么实现的&#xff1f;秒杀项目中显示登录用户信息怎么实现的&#xff1f;SessionStorage是什么?为什么不用session而用token什么是…

初识C语言——第二十五天

函数的嵌套调用和链式访问 函数不可以嵌套定义&#xff0c;但可以嵌套调用 链式访问&#xff1a;把一个函数的返回值作为另外一个函数的参数 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>//写一个函数&#xff0c;每调用一次这个函数&#xff0c;就会 将num…

数据结构之时间复杂度和空间复杂度的相关计算

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 时间复杂度 概念 大O的渐进表示法 相关练习 例1&#xff1a; 例2&#xff1a; 例3&am…

可转债日内自动T+0交易,行情推送+策略触发+交易接口

说明 目前这个项目已编译打包,下载即可测试,直接生成多平台可执行文件&#xff0c;详见运行方法。行情部分与策略弱相关&#xff0c;拆分解耦单独作为一个项目。行情项目请移步GitHub - freevolunteer/hangqing: A股行情订阅工具&#xff0c;支持股票/可转债level2/level2数据&…

MySQL主从复制(三):主从延迟

主备流程图&#xff1a; 谈到主备的复制能力&#xff0c;要关注的是上图中的两个黑色箭头。 一个箭头代表了客户端写入主库&#xff0c;另一个箭头代表的是sql_thread执行中转日志&#xff08;relay log&#xff09;。如果用箭头的粗细来代表并行度的话&#xff0c;那么真实情…

svg中path的直线命令使用

path路径 <path>元素是SVG基本形状中最强大的一个。可以使用它来创建线条&#xff0c;曲线&#xff0c;弧形等等。 另外&#xff0c;path只需要设定很少的点&#xff0c;就可以创建平滑流畅的线条&#xff08;比如曲线&#xff09;。虽然polygon元素也可以实现类似的效…