Sping源码(八)—registerBeanPostProcessors

news2024/10/5 15:34:16

序言

之前我们用大量的篇幅介绍过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;
	}
}

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

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

相关文章

【C语言】深入理解指针(一)(上)

本篇文章将讲解&#xff1a; &#xff08;1&#xff09;内存和地址 &#xff08;2&#xff09;指针变量和细致 &#xff08;3&#xff09;指针变量类型的意义 一&#xff1a;内存和地址 &#xff08;1&#xff09;内存 在讲内存和地址之前&#xff0c;我们讲一个生活中的…

混合组网VS传统网络:智能硬件混合组网优劣势浅要解析

智能硬件混合组网是一种利用多种通信技术相结合的方法&#xff0c;以实现更灵活、更可靠的网络连接。通过蓝牙、Wi-Fi、LoRa、4G相互之间的不同通讯方式&#xff0c;根据应用场景的不同以及现场实际环境&#xff0c;优选最佳物联网混合组网方案&#xff0c;以达到部署最便捷性价…

618知识狂欢,挑本好书,点亮智慧生活!

618精选编程书单&#xff1a;提升你的代码力 一年一度的618又到啦&#xff01;今年的618就不要乱买啦&#xff0c;衣服买多了会被淘汰&#xff0c;电子产品买多了会过时&#xff0c;零食买多了会增肥&#xff0c;最后怎么看都不划算。可是如果你购买知识&#xff0c;坚持阅读&a…

2024年了, 你还不会使用node.js做压力测试?

前些天刷抖音&#xff0c;看到网传的Java继父&#xff0c;求人攻击压测他的网站&#xff0c;这不得摩拳擦掌。 所以今天来聊聊如何对自己的项目、接口进行压力测试。 压力测试的目的 首先, 绝对不是为了压测、攻击别人的网站为乐。 1、探索线上系统流量承载的极限&#xff…

鲁教版六年级数学下册-笔记

文章目录 第五章 基本平面图形1 线段、射线、直线2 比较线段的长短3 角4 角的比较5 多边形和圆的初步认识第六章 整式的乘除1 同底数幂的乘法2 幂的乘方与积的乘方3 同底数幂的除法4 零指数幂与负整数指数幂5 整式的乘法6 平方差公式7 完全平方公式8 整式的除法 第七章 相交线与…

保障餐饮场所安全:定期送检可燃气体报警器

在餐饮行业&#xff0c;火灾隐患一直备受关注。餐厅、茶饮店等场所常常使用燃气设备&#xff0c;而这些设备带来了潜在的安全隐患。 为了及时发现并预防可燃气体泄漏&#xff0c;可燃气体报警器的定期送检显得尤为重要。那么&#xff0c;为什么可燃气体报警器需要定期送检呢&a…

20.有序性与内存屏障

文章目录 有序性与内存屏障1.重排序1.1.编译器重排序1.2.CPU重排序1.2.1.指令级重排序1.2.2.内存系统重排序1.3.As-if-Serial规则 2.内存屏障2.1.硬件层面的内存屏障2.1.2.写屏障2.1.3.读屏障2.1.4.全屏障 2.2.硬件层的内存屏障作用2.3.案例 有序性与内存屏障 有序性 与 可见性…

基于英飞凌BGT60LTR11AIP E6327芯片具低功耗的脉冲多普勒操作模式常用于汽车应用的雷达上

芯片特征&#xff1a; 60 GHz收发器MMIC&#xff0c;带一个发射器和一个接收器单元封装天线&#xff08;AIP&#xff09;&#xff08;6.73.30.56 mm3)低功耗的脉冲多普勒操作模式自主模式用于运动和运动方向的集成检测器运动检测信号的直接输出目标检测范围的15个可配置阈值检测…

汇编-16位汇编环境搭建

16位汇编环境 在学习16位汇编时&#xff0c;我选择的环境是在VMware中安装Windows XP虚拟机来学习&#xff1b;因为Windows XP提供了兼容的DOS环境&#xff0c;可以直接运行和调试16位汇编程序&#xff1b;在win10&#xff0c;win11环境中原生不支持直接运行 16 位程序&#x…

华为鸿蒙认证培训 | 讯方技术成为首批鸿蒙原生应用开发及培训服务商

5月20日&#xff0c;鸿蒙原生应用合作交流推介会-深圳站在深圳中洲万豪酒店隆重举行。讯方技术作为鸿蒙钻石服务商受邀参与此次活动&#xff0c;活动由讯方技术总裁刘国锋、执行副总裁刘铭皓、教学资源部部长张俊豪共同出席。 本次活动由深圳政府指导&#xff0c;鸿蒙生态官方…

微服务项目收获和总结---第4天(文章审核和保存)

文章审核以及APP端保存文章 业务流程&#xff1a; App端保存接口&#xff1a; 数据库表详情 文章的基本信息表&#xff1a;id&#xff0c;标题&#xff0c;作者id&#xff0c;频道id...... 文章的权限/配置表&#xff1a;存储文章是否可以评论&#xff0c;是否上架&#xff…

eclipse配置JDK和Tomcat

eclipse配置JDK jdk配置 配置JDK&#xff1a; 首先&#xff0c;确保JDK已经安装并配置了环境变量。这包括设置JAVA_HOME环境变量&#xff0c;指向JDK的安装目录&#xff0c;以及更新CLASSPATH和PATH环境变量以包含JDK的bin目录。 在Eclipse中&#xff0c;通过Window > Pre…

【设计模式深度剖析】【4】【创建型】【建造者模式】| 类比选购汽车的过程,加深理解

&#x1f448;️上一篇:抽象工厂模式 | 下一篇:原型模式&#x1f449;️ 目录 建造者模式概览定义英文原话直译如何理解呢&#xff1f;建造者模式将对象的建造过程给抽象出来了类比选购汽车 4个角色UML类图1. 抽象建造者&#xff08;Builder&#xff09;角色2. 具体建造者…

02.爬虫---HTTP基本原理

02.HTTP基本原理 1.URI 和 URL 的区别2.HTTP 和 HTTPS 的区别3.请求过程 1.URI 和 URL 的区别 URL&#xff08;Uniform Resource Locator&#xff09;即-统一资源定位符 URL是用来定位和访问互联网上资源的独特标识&#xff0c;它包括了资源的位置&#xff08;如IP地址或域名&a…

Docker-制作镜像的两种方式=》基于容器制作基于Dockerfile制作

本文主要是基于Docker如何制作一个Java镜像&#xff0c;而一个Java镜像想要运行需要系统环境&#xff0c;JDK。所以我们要先有一个系统环境&#xff0c;本文使用的是centos7&#xff0c;JDK选择版本是8&#xff0c;而我使用的Java程序是一个简易的springBoot项目&#xff0c;你…

详细分析Vue按钮间距的优化方式(附Demo)

目录 前言1. 按钮间距2. 垂直间距 前言 正常间距如下&#xff1a; 其Demo如下&#xff1a; <el-table-column label"操作" align"center"><template #default"scope"><el-buttonlinktype"primary"click"openFor…

Node.js —— 前后端的身份认证 之用 express 实现 JWT 身份认证

JWT的认识 什么是 JWT JWT&#xff08;英文全称&#xff1a;JSON Web Token&#xff09;是目前最流行的跨域认证解决方案。 JWT 的工作原理 总结&#xff1a;用户的信息通过 Token 字符串的形式&#xff0c;保存在客户端浏览器中。服务器通过还原 Token 字符串的形式来认证用…

Mysql注入详细讲解

特殊字符 0x3a:0x7e~0x23# 注入基础 联合查询注入(union) :::tips 页面将SQL查询内容显示出来&#xff0c;即为有回显&#xff0c;可以尝试联合查询注入 利用关键字union &#xff0c;union all 拼接恶意SQL语句 ::: 注入流程 有报错&#xff0c;可以利用报错。如&#xff…

[datawhale202405]从零手搓大模型实战:TinyAgent

结论速递 TinyAgent项目实现了一个简单的Agent智能体&#xff0c;主要是实现了ReAct策略&#xff08;推理调用工具的能力&#xff09;&#xff0c;及封装了一个Tool。 项目实现有一定的疏漏。为了正确运行代码&#xff0c;本次对代码Agent部分进行了简单修改&#xff08;完善…

VBA语言専攻每周通知20240524

通知20240524 各位学员∶本周MF系列VBA技术资料增加611-615讲&#xff0c;T3学员看到通知后请免费领取,领取时间5月24日晚上18:00-5月26日晚上18:00。本次增加内容&#xff1a; MF611:用InputBox录入日期 MF612:信息提示10秒后关自动关闭 MF613:只是信息提示10秒 MF614:显…