Spring核心--Bean后处理器
Spring的后处理器(Spring核心重点)
Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:
· BeanFactoryPostProcessor: Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
· BeanPostProcessor: Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。
Bean工厂后处理器 – BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。
BeanFactoryPostProcessor 定义如:
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}
编写BeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{System.out.println("MyBeanFactoryPostProcessor执行了...");}
}
配置BeanFactoryPostProcessor
<bean class="com.itheima.processor.MyBeanFactoryPostProcessor"/>
postProcessBeanFactory 参数本质就是 DefaultListableBeanFactory,拿到BeanFactory的引用,自然就可以对beanDefinitionMap中的BeanDefinition进行操作了 ,例如对UserDaoImpl的BeanDefinition进行修改操作
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition userDaoBD = beanFactory.getBeanDefinition(“userDao”);//获得UserDao定义对象userDaoBD.setBeanClassName("com.itheima.dao.impl.UserDaoImpl2"); //修改class//userDaoBD.setInitMethodName(methodName); //修改初始化方法//userDaoBD.setLazyInit(true); //修改是否懒加载//... 省略其他的设置方式 ...}
}
上面已经对指定的BeanDefinition进行了修改操作,下面对BeanDefiition进行注册操作
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {//强转成子类DefaultListableBeanFactoryif(configurableListableBeanFactory instanceof DefaultListableBeanFactory){DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");//进行注册操作beanFactory.registerBeanDefinition("userDao2",beanDefinition);}}
}
Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作
public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");beanDefinitionRegistry.registerBeanDefinition("userDao2",beanDefinition);}
}
使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描
1.自定义@MyComponent注解,使用在类上
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {//显示的指定Bean的beanNameString value() default "";
}
2.在类上使用@MyComponent
@MyComponent("otherBean")
public class OtherBean {
}
3.自定义BeanFactoryPostProcessor完成注解解析
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//指定要扫描的包String basePackage = "com.itheima";//调用扫描工具扫描指定包及其子包下的@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();}});}
BeanFactoryPostProcessor 在SpringBean的实例化过程中的体现

Bean后处理器 – BeanPostProcessor
Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。
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;}
}
自定义MyBeanPostProcessor,完成快速入门测试
public class MyBeanPostProcessor implements BeanPostProcessor {/* 参数: bean是当前被实例化的Bean,beanName是当前Bean实例在容器中的名称
返回值:当前Bean实例对象 */public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的before方法...");return bean;}/* 参数: bean是当前被实例化的Bean,beanName是当前Bean实例在容器中的名称
返回值:当前Bean实例对象 */public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("BeanPostProcessor的after方法...");return bean;}
}
配置MyBeanPostProcessor
<bean class="com.itheima.processors.MyBeanPostProcessor"></bean>
测试控制台打印结果如下:
UserDaoImpl创建了...
UserDaoImpl属性填充...
BeanPostProcessor的before方法...
UserDaoImpl初始化方法执行...
BeanPostProcessor的after方法...
编写BeanPostProcessor,增强逻辑编写在 after方法中
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//对Bean进行动态代理,返回的是Proxy代理对象Object proxyBean = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {long start = System.currentTimeMillis();System.out.println("开始时间:" + new Date(start));//执行目标方法Object result = method.invoke(bean, args);long end = System.currentTimeMillis();System.out.println("结束时间:" + new Date(end));return result;});//返回代理对象return proxyBean;
}
对Bean方法进行执行时间日志增强
编写BeanPostProcessor,增强逻辑编写在 after方法中
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//对Bean进行动态代理,返回的是Proxy代理对象Object proxyBean = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {long start = System.currentTimeMillis();System.out.println("开始时间:" + new Date(start));//执行目标方法Object result = method.invoke(bean, args);long end = System.currentTimeMillis();System.out.println("结束时间:" + new Date(end));return result;});//返回代理对象return proxyBean;
}
BeanPostProcessor 在 SpringBean的实例化过程中的体现

相关文章:
Spring核心--Bean后处理器
Spring的后处理器(Spring核心重点) Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器: BeanFactoryPostProcessor: Bean工…...
Windows子系统Ubuntu本地部署xinference以及接入dify详解
背景介绍 系统:Ubuntu 22.04.5 LTSpython环境管理工具:mincondadify版本:0.13.2本文参考 Xinference在线文档和dify的官方介绍模型接入 1. Github拉取Xinference代码 首选去Xinference的Github地址拉取代码 2. 在minconda创建隔离环境 - xinfernce 是我本地创建的环境名…...
如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?
在面向对象编程中,接口继承和实现继承是两个重要的概念,同时多态性也是面向对象编程的一大特性,但在追求多态性的同时,我们也需要考虑性能问题。本文将详细探讨接口继承与实现继承的区别,以及如何处理多态性与性能的平…...
VR虚拟展厅的实时互动是如何实现的?
VR虚拟展厅的实时互动是通过一系列技术和流程实现的,这些技术和流程共同确保了用户在虚拟环境中的互动体验能够及时响应和更新。 接下来,由专业从事VR虚拟展厅制作的圆桌3D云展厅平台为大家介绍一下实现VR虚拟展厅实时互动的几个关键要素: 高…...
Java、鸿蒙与嵌入式开发:技术选择与职业发展分析
在当今快速发展的科技领域中,Java、鸿蒙和嵌入式开发代表着不同的技术方向和职业机遇。每个方向都有其独特的市场价值和发展前景,让我们深入分析这三个领域的特点、发展趋势和职业规划。 Java开发方向已经发展了二十多年,仍然在软件开发领域…...
28. Three.js案例-创建圆角矩形并进行拉伸
28. Three.js案例-创建圆角矩形并进行拉伸 实现效果 知识点 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染 3D 场景的主要渲染器。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数,可选。 …...
Shopee算法分析 - x-sap-ri
去除干扰项 在上篇文章中说到, 我们主动调用了几次,返回结果都是不同的 相同参数, 我们主动多次call. 可以看到结果是不同的. 只有一个Key不同. 接下来, 引用龙哥的文章 引用自龙哥文章, 我仅仅是对关键信息做加粗 1.1 引言 在使用 Unidbg 模拟执行以及辅助算法还原时&#x…...
日志相关的学习记录
Logger.error还不知道怎么传参打印?看完这个你就明白了-CSDN博客 日志使用的方式 使用e.getMessage()、e .toString() 都不会打印堆栈信息,最好直接打印e。 当使用两个参数error(String message, Throwable t),且第二个参数为Throwable(就是…...
HTML和JavaScript实现商品购物系统
下面是一个更全面的商品购物系统示例,包含新增商品、商品的增加删除以及结算找零的功能。这个系统使用HTML和JavaScript实现。 1.功能说明: 这个应用程序使用纯HTML和JavaScript实现。 包含一个商品列表和一个购物车区域。商品列表中有几个示例商品&a…...
深度学习中的激活函数
激活函数(activation function)是应用于网络中各个神经元输出的简单变换,为其引入非线性属性,使网络能够对更复杂的数据进行建模,使其能够学习更复杂的模式。如果没有激活函数,神经元只会对输入进行枯燥的线性数学运算。这意味着&…...
编写php项目所需环境
需要编写php项目,需要看到编写的代码展现的效果,这里我选择用xampp来展现 准备工作: https://learncodingfast.com/how-to-install-xampp-and-brackets/#Installing_and_Running_XAMPP xampp下载地址:https://www.apachefriends.…...
华为机试HJ108 求最小公倍数
首先看一下题 描述 正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。 数据范围: 1≤a,b≤100000 输入描述: 输入两个正整数A和B。 输出描述: 输出A和B的最小公…...
【Python技术】同花顺wencai涨停分析基础上增加连板分析
周末,有读者加我, 说 之前的涨停分析 是否可以增加连板分析。 这个可以加上。 先看效果 这里附上完整代码: import streamlit as st import pywencai import pandas as pd from datetime import datetime, timedelta import plotly.graph_o…...
《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五)
《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…...
【LeetCode】3356、零数组变换 II
【LeetCode】3356、零数组变换 II 文章目录 一、数据结构-差分-一维差分、二分1.1 数据结构-差分-一维差分、二分1.1.1 题意复述1.1.2 思路1.1.3 手写二分1.1.4 sort.Search() 二分1.1.5 sort.Find() 二分 二、多语言解法 一、数据结构-差分-一维差分、二分 1.1 数据结构-差分…...
Vue 子组件修改父组件传过来的值的三种方式
方式1:子组件发送emit,触发父组件修改 父组件 <template><div><son :count"count" updateCount"updateCount" /></div> </template><script> import son from "./son"; export def…...
4.Python 数字类型
Python 数字类型总结 文章目录 Python 数字类型总结1. 数字类型概述特点 2. 数字类型的创建与赋值3. 数字类型转换4. 数学运算与函数math 模块cmath 模块 5. 随机数生成6. 三角函数7. 数学常量 总结 Python 提供了多种数字类型来存储和操作数值数据。这些类型包括整数、浮点数、…...
MacOs 日常故障排除troubleshooting
1. 关闭开机自启动 app X macOs 15.1 System settings -> General -> Login Items & Extensions->Open at Login -> Select app X and click -...
(补)算法刷题Day19:BM55 没有重复项数字的全排列
题目链接 给出一组数字,返回该组数字的所有排列 例如: [1,2,3]的所有排列如下 [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1]. (以数字在数组中的位置靠前为优先级,按字典序排列输出。) 思路: 使用回…...
golang中的值传递与引用传递,如何理解结构体的方法?
先从一个例子说起 type Counter struct {count int }func (c Counter) Inc() {c.count }func test1() {c : Counter{}do : func() {for i : 0; i < 10; i {c.count}fmt.Println("done")}go do()go do()time.Sleep(3 * time.Second)fmt.Println(c.count) }func te…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
如何把工业通信协议转换成http websocket
1.现状 工业通信协议多数工作在边缘设备上,比如:PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发,当设备上用的是modbus从站时,采集设备数据需要开发modbus主站;当设备上用的是西门子PN协议时…...
