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…...
从根源到优化:Visual C++ Redistributable AIO工具的5个技术维度解析
从根源到优化:Visual C Redistributable AIO工具的5个技术维度解析 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 问题溯源:运行库故障的…...
BilibiliDown:三步实现B站音频高效提取与批量处理全攻略
BilibiliDown:三步实现B站音频高效提取与批量处理全攻略 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors…...
OmenSuperHub:硬件控制与性能优化的开源工具解决方案
OmenSuperHub:硬件控制与性能优化的开源工具解决方案 【免费下载链接】OmenSuperHub 使用 WMI BIOS控制性能和风扇速度,自动解除DB功耗限制。 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub OmenSuperHub是一款专为惠普暗影精灵系列…...
IwrQk实战指南:跨平台Iwara视频社区客户端从安装到精通
IwrQk实战指南:跨平台Iwara视频社区客户端从安装到精通 【免费下载链接】iwrqk Unofficial Iwara Flutter Client 项目地址: https://gitcode.com/gh_mirrors/iw/iwrqk IwrQk是一款基于Flutter开发的跨平台Iwara视频社区客户端,专为技术爱好者和普…...
AI辅助开发:借助快马智能模型为华网三百每年cn官网打造咨询聊天机器人
AI辅助开发:借助快马智能模型为华网三百每年cn官网打造咨询聊天机器人 最近在给华网三百每年cn官网开发一个在线咨询聊天机器人组件,整个过程让我深刻体会到AI辅助开发的便利性。通过InsCode(快马)平台集成的AI模型,我不仅快速完成了前端组件…...
【MicroPython编程-ESP32篇:设备驱动】-PCF8591数据采集驱动
PCF8591数据采集驱动 文章目录 PCF8591数据采集驱动 1、PCF8591介绍 2、软件准备 3、硬件准备与接线 4、程序实现 4.1 PCF8591驱动实现 4.2 主程序 1、PCF8591介绍 PCF8591 是一款单片集成、独立电源、低功耗、8 位 CMOS 数据采集设备。 PCF8591 具有四个模拟输入、一个模拟输…...
AI时代下的AOSP构建:从“效率黑洞”到“分钟级交付”,企业级构建如何破局?
近年来,AI模型训练与大型软件构建的复杂度持续攀升,企业级操作系统的多分支、多产品构建正成为工程团队的“效率黑洞”。在 Android 平台,AOSP 构建尤为突出:全量构建耗时长、增量改动触发大规模重建、CI 队列冗长、资源消耗高等问…...
文档格式高效破解:NCMDump实现加密文件自由掌控全指南
文档格式高效破解:NCMDump实现加密文件自由掌控全指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 在数字化办公时代,你是否曾因收到的加密文档无法跨平台打开而错失重要信息?是否经历过花费数…...
GTE+SeqGPT部署教程:Windows WSL2环境下GTE+SeqGPT全链路运行指南
GTESeqGPT部署教程:Windows WSL2环境下GTESeqGPT全链路运行指南 想自己动手搭建一个能“理解”你问题、还能“回答”你的AI小助手吗?今天,我们就来玩点实在的——在Windows电脑上,通过WSL2(Windows Subsystem for Lin…...
Qwen3-ForcedAligner-0.6B完整指南:音频格式支持/实时录音/时间戳导出全解析
Qwen3-ForcedAligner-0.6B完整指南:音频格式支持/实时录音/时间戳导出全解析 你是不是也遇到过这样的烦恼?开会录音想整理成文字,手动打字累到怀疑人生;做视频需要加字幕,一句一句对时间轴对到眼花。今天要介绍的这个…...
