当前位置: 首页 > news >正文

深入Spring底层透析后置处理器之豁然开朗篇

目录

  • 前言
  • Spring的后置处理器
    • Bean工厂后置处理器
    • Bean后置处理器
  • 自定义@Component实现注解开发

前言

看这篇文章之前,需要了解Bean创建的过程,本篇文章是接着bean创建的基本流程的续写
Bean创建的基本过程:http://t.csdn.cn/1lK2d


Spring的后置处理器

熟悉Bean创建的基本流程是前提

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行

那Spring的后置处理器有什么用处呢?
不知道你看到它可以动态注册BeanDefinition时有什么想法,对,你想的没错,注解开发原理中就是用Spring的后置处理器来动态创建Bean对象的,别眨眼,接下来就时见证奇迹的时刻


Bean工厂后置处理器

Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;也就是当把xml中所有bean配置信息封装成BeanDefinition对象,装到BeanDefinitionMap集合后,但还没有反射创建bean对象时,再往map中注册BeanDefinition对象,后续反射就会创建出新的xml中未定义的对象


Bean工厂后处理器 – BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,在BeanDefinitionMap填充完毕后,Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

所以它的使用分以下几步

  • 创建一个处理器类实现BeanFactoryPostProcessor接口
  • 重写BeanFactoryPostProcessor的方法
  • 交给Spring容器管理(配置到xml中或加注解)

使用方式如下

在这里插入图片描述


由于BeanDefinition是接口,我们要new 一个BeanDefinition对象,就要new 它的一个实现类RootBeanDefinition对象

在这里插入图片描述


其中需要强转为DefaultListableBeanFactory是因为,ConfigurableListableBeanFactory的对象无法把beanDefinition注册到map中,BeanDefinitionMap是DefaultListableBeanFactory中定义的集合,而DefaultListableBeanFactory又是实现了ConfigurableListableBeanFactory的接口,所以强转一下。

在这里插入图片描述

不得不说,这个源码自己也需要多看,不然这些接口名类名是什么,继承了什么,有什么关键成员变量都不清楚,看这些调用关系自然就云里雾里


Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {//这个方法是BeanFactoryPostProcessor接口的方法,重写一下就不用管了@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.dao.UserDaoImpl");//要创建的bean的位置//注册beanDefinitionbeanDefinitionRegistry.registerBeanDefinition("userDao",beanDefinition);}
}

最后main方法中调用时

UserDao userDao = applicationContext.getBean(UserDao.class)

在这里插入图片描述


Bean后置处理器

Bean后处理器 – BeanPostProcessor

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。


bean后处理器的使用步骤和bean工厂后处理器基本类似,只是处理时机不一样,bean工厂后处理器在填充map后,实例化前;bean后处理器在实例化后,添加单例池前

  • 创建后处理器类(自己随便创建一个就行)
  • 实现 BeanPostProcessor接口,重写它的方法
  • 把后处理器类交由bean管理

BeanPostProcessor的接口定义如下(模板):

public interface BeanPostProcessor {@Nullable//表示该方法可以不写//在属性注入完毕,init初始化方法执行之前被回调default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullable//在初始化方法执行之后,被添加到单例池singletonObjects之前被回调default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

在这里插入图片描述


自定义@Component实现注解开发

  • 自定义@MyComponent注解,使用在类上;
  • 使用包扫描器工具BaseClassScanUtils 完成指定包的类扫描;
  • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最终被Spring管理。(注意实现BeanFactoryPostProcessor接口的类需要交由Spring管理)

原理大概就是用包扫描工具类,指定包及其子包下的类上加了自定义注解的类名获取并添加到一个map集合中,然后遍历依次对它们进行包装成一个个BeanDefinition对象,然后再它们注册到BeanDefinitionMap集合中,后续反射创建bean时,这些注解添加的bean也会被创建。

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//指定要扫描的包String basePackage = "com";//调用扫描工具BaseClassScanUtils扫描指定包及其子包下的@MyComponentMap<String, Class> myComponentClassMap = BaseClassScanUtils.scanMyComponentAnnotation(basePackage);//遍历Map集合,创建BeanDefinition对象进行注册myComponentClassMap.forEach((beanName,clazz)->{try {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(clazz.getName());registry.registerBeanDefinition(beanName,beanDefinition);} catch (Exception e) {e.printStackTrace();}});}

不得不说有那味了

相关文章:

深入Spring底层透析后置处理器之豁然开朗篇

目录前言Spring的后置处理器Bean工厂后置处理器Bean后置处理器自定义Component实现注解开发前言 看这篇文章之前&#xff0c;需要了解Bean创建的过程&#xff0c;本篇文章是接着bean创建的基本流程的续写 Bean创建的基本过程&#xff1a;http://t.csdn.cn/1lK2d Spring的后置处…...

软件测试(基础定义篇)

测试基础 1、什么是软件测试&#xff1f;2、常见的测试分类3、质量模型 4、软件测试流程 5、测试用例 6、测试用例设计方法 )1、什么是软件测试&#xff1f; 1、什么是软件&#xff1f; 答&#xff1a;软件是控制计算机硬件工作的工具。 2、软件的组成&#xff1f; 3、什么是…...

华为OD机试 - 寻找目标字符串 | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...

使用echart绘制中国地图并显示人数

文章目录引言效果如图所示vue中echarts4.9版本&#xff0c;地图的使用引言 在做毕设的过程中&#xff0c;有一个需求&#xff1a;根据用户的ip&#xff0c;在前端展示出中国地图&#xff0c;然后展现出每个省有多少人这样子 经过百度后&#xff0c;发现可以使用echart来完成该…...

Git的常用命令

1&#xff1a;软件安装1.1&#xff1a;Git下载与安装百度上搜索Git官网&#xff1a;https://git-scm.com/下载&#xff1a;https://git-scm.com/download/win下载Git安装程序&#xff0c;双击安装 Git-2.9.3.2-64-bit.exe配置环境变量path 使用git --version查看 git 是否安装成…...

AcWing1018.最低通行费

1018.最低通行费一个商人穿过一个 NN 的正方形的网格&#xff0c;去参加一个非常重要的商务活动。他要从网格的左上角进&#xff0c;右下角出。每穿越中间 1 个小方格&#xff0c;都要花费 1 个单位时间。商人必须在 (2N−1)(2−1) 个单位时间穿越出去。而在经过中间的每个小方…...

【面试题】vue中的插槽是什么?

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库一、slot是什么在HTML中 slot 元素 &#xff0c;作为 Web Components 技术套件的一部分&#xff0c;是Web组件内的一个占位符该占位符可以在后期…...

Go语言结构体struct详解,Go空结构体的这些妙用你知道吗?

本文详解了Go语言结构体的各个知识点&#xff0c;最后介绍了空结构体的3种妙用。希望对你有帮助。 定义 结构体&#xff0c;是一种自定义的数据类型&#xff0c;由多个数据类型组合而成。用于描述一类事物相关属性。 定义方式&#xff1a; type 类型名 struct {字段名 字段类…...

华为OD机试 - 航天器(Python) | 机试题+算法思路+考点+代码解析 【2023】

航天器 题目 给航天器一侧加装长方形和正方形的太阳能板(图中的斜线区域); 需要先安装两个支柱(图中的黑色竖条); 再在支柱的中间部分固定太阳能板; 但航天器不同位置的支柱长度不同; 太阳能板的安装面积受限于最短一侧的那支支柱的长度; 现提供一组整型数组的支柱高度数据;…...

【Optional】告别丑陋判空,使用Optional类

一、概述 当项目中充斥着大量的、丑陋的判空语句&#xff0c;如下&#xff1a; if (user ! null) {Address address user.getAddress();if (address ! null) {Country country address.getCountry();if (country ! null) {String isocode country.getIsocode();if (isocod…...

魔兽世界服务端端新手搭建教程

明杰也是很久以前开始研究魔兽服务器架设&#xff0c;主要原因是亚服经常要排队6-7个小时&#xff0c;去不排除的服和单机没啥区别&#xff0c;以怀旧服玩到10级以后就开始玩335端&#xff0c;一开始也和新入手的人一样云里雾里的&#xff0c;经过长时间的学习总算有点成就,向新…...

宝塔搭建实战人才求职管理系统mobile手机端vue源码(五)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上一期给大家分享骑士cms会员管理member前端vue在本地运行打包、宝塔发布部署的方式&#xff0c;本期给大家分享&#xff0c;mobile移动端vue怎么在本地运行&#xff0c;打包&#xff0c;实现线上功能更新替换的方…...

生态应用:探讨 NGINX 与上下游系统集成时的开发经验

NGINX 作为一款高性能的 Web 服务器和反向代理服务器&#xff0c;在各种应用场景中广泛应用。随着业务的发展&#xff0c;我们在使用 NGINX 时&#xff0c;可能需要将其与其他系统进行集成&#xff0c;以实现更加复杂的业务需求。 本文将结合实际应用场景&#xff0c;探讨 NGI…...

ArcGIS批量拼接大量栅格遥感影像:Mosaic工具

本文介绍在ArcGIS下属的ArcMap软件中&#xff0c;基于Mosaic工具&#xff0c;批量对大量栅格遥感影像文件加以拼接、镶嵌的方法。 在GIS应用中&#xff0c;我们时常需要对大量栅格遥感影像数据加以批量拼接的工作。这一步骤可以基于Python语言实现&#xff0c;具体可以参考文章…...

Flink UI部署jar包报错

错误描述&#xff1a; 通过Flink的UI中的Submit New Job菜单添加jar包的时候提示报错。报错信息的关键字是“The LocalStreamEnvironment cannot be used when submitting a program through a client, or running in a TestEnvironment context”&#xff0c;最关键的是“Loc…...

Linux就该这么学:RAID与LVM磁盘阵列技术

这里写目录标题 7.1.1 部署磁盘阵列7.1.2 损坏磁盘阵列及修复7.1.3 磁盘阵列+备份盘7.1.4 删除磁盘阵列1. 需要将所有的磁盘都设置成停用状态:2. 逐一移除出去3. 续停用整个RAID磁盘阵列7.2 LVM逻辑卷管理器7.2.1 部署逻辑卷7.2.2 扩容逻辑卷7.2.3 缩小逻辑卷7.2.4 逻辑卷快照…...

Prometheus+Grafana监控

1、简介1.1 Prometheus官网地址&#xff1a;https://prometheus.io/Prometheus是一个开源的监控系统&#xff0c;起源于SoundCloud。它由以下几个核心组件构成&#xff1a;数据爬虫&#xff1a; 根据配置的时间定期的通过HTTP抓去metrics数据。time-series 数据库&#xff1a; …...

【JUC2022】第三章 线程中断与 LockSupport

【JUC2022】第三章 线程中断与 LockSupport 文章目录【JUC2022】第三章 线程中断与 LockSupport一、线程中断1.什么是中断机制2.中断 API3.代码实现4.Thread.sleep()二、LockSupport1.什么是 LockSupport2.代码实现3.总结一、线程中断 1.什么是中断机制 首先&#xff0c;一个…...

数据结构刷题(七):202快乐数、1两数之和、454四数相加II、15三数之和、18四树之和

1.快乐数题目链接思路&#xff1a;使用set&#xff0c;当set中出现相同元素时&#xff0c;返回false注意&#xff1a;while循环中语句顺序&#xff1b; 除数取余。解法&#xff1a;public boolean isHappy(int n){Set<Integer> res new HashSet<>();int[] arr ne…...

华为机试题:HJ80 整型数组合并(python)

文章目录知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。  1.1、int(input()) 与 map(int, input().spilt()) 的区别  1.2、input() 与 list(input()) 的区别、及其相互转换方法2、print() &#xff1a;打印输出…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...