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

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 是我本地创建的环境名…...

如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?

在面向对象编程中&#xff0c;接口继承和实现继承是两个重要的概念&#xff0c;同时多态性也是面向对象编程的一大特性&#xff0c;但在追求多态性的同时&#xff0c;我们也需要考虑性能问题。本文将详细探讨接口继承与实现继承的区别&#xff0c;以及如何处理多态性与性能的平…...

VR虚拟展厅的实时互动是如何实现的?

VR虚拟展厅的实时互动是通过一系列技术和流程实现的&#xff0c;这些技术和流程共同确保了用户在虚拟环境中的互动体验能够及时响应和更新。 接下来&#xff0c;由专业从事VR虚拟展厅制作的圆桌3D云展厅平台为大家介绍一下实现VR虚拟展厅实时互动的几个关键要素&#xff1a; 高…...

Java、鸿蒙与嵌入式开发:技术选择与职业发展分析

在当今快速发展的科技领域中&#xff0c;Java、鸿蒙和嵌入式开发代表着不同的技术方向和职业机遇。每个方向都有其独特的市场价值和发展前景&#xff0c;让我们深入分析这三个领域的特点、发展趋势和职业规划。 Java开发方向已经发展了二十多年&#xff0c;仍然在软件开发领域…...

28. Three.js案例-创建圆角矩形并进行拉伸

28. Three.js案例-创建圆角矩形并进行拉伸 实现效果 知识点 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染 3D 场景的主要渲染器。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数&#xff0c;可选。 …...

Shopee算法分析 - x-sap-ri

去除干扰项 在上篇文章中说到, 我们主动调用了几次,返回结果都是不同的 相同参数, 我们主动多次call. 可以看到结果是不同的. 只有一个Key不同. 接下来, 引用龙哥的文章 引用自龙哥文章, 我仅仅是对关键信息做加粗 1.1 引言 在使用 Unidbg 模拟执行以及辅助算法还原时&#x…...

日志相关的学习记录

Logger.error还不知道怎么传参打印&#xff1f;看完这个你就明白了-CSDN博客 日志使用的方式 使用e.getMessage()、e .toString() 都不会打印堆栈信息&#xff0c;最好直接打印e。 当使用两个参数error(String message, Throwable t)&#xff0c;且第二个参数为Throwable(就是…...

HTML和JavaScript实现商品购物系统

下面是一个更全面的商品购物系统示例&#xff0c;包含新增商品、商品的增加删除以及结算找零的功能。这个系统使用HTML和JavaScript实现。 1.功能说明&#xff1a; 这个应用程序使用纯HTML和JavaScript实现。 包含一个商品列表和一个购物车区域。商品列表中有几个示例商品&a…...

深度学习中的激活函数

激活函数(activation function)是应用于网络中各个神经元输出的简单变换&#xff0c;为其引入非线性属性&#xff0c;使网络能够对更复杂的数据进行建模&#xff0c;使其能够学习更复杂的模式。如果没有激活函数&#xff0c;神经元只会对输入进行枯燥的线性数学运算。这意味着&…...

编写php项目所需环境

需要编写php项目&#xff0c;需要看到编写的代码展现的效果&#xff0c;这里我选择用xampp来展现 准备工作&#xff1a; https://learncodingfast.com/how-to-install-xampp-and-brackets/#Installing_and_Running_XAMPP xampp下载地址&#xff1a;https://www.apachefriends.…...

华为机试HJ108 求最小公倍数

首先看一下题 描述 正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值&#xff0c;设计一个算法&#xff0c;求输入A和B的最小公倍数。 数据范围&#xff1a; 1≤a,b≤100000 输入描述&#xff1a; 输入两个正整数A和B。 输出描述&#xff1a; 输出A和B的最小公…...

【Python技术】同花顺wencai涨停分析基础上增加连板分析

周末&#xff0c;有读者加我&#xff0c; 说 之前的涨停分析 是否可以增加连板分析。 这个可以加上。 先看效果 这里附上完整代码&#xff1a; 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&#xff1a;子组件发送emit&#xff0c;触发父组件修改 父组件 <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 没有重复项数字的全排列

题目链接 给出一组数字&#xff0c;返回该组数字的所有排列 例如&#xff1a; [1,2,3]的所有排列如下 [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1]. &#xff08;以数字在数组中的位置靠前为优先级&#xff0c;按字典序排列输出。&#xff09; 思路&#xff1a; 使用回…...

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…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...