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

Spring的后处理器-BeanFactoryPostprocessor

目录

Spring后处理器

Bean工厂后处理器-BeanFactoryPostProcessor

修改beanDefinition对象

添加beanDefiniton对象

方法一

方法二

自定义@Component


Spring后处理器

  • Spring后处理器是Spring对外开放的重要拓展点(让我们可以用添加自己的逻辑),允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition(向BeanDefitionMap中添加BeanDefition对象的过程),动态修改BeanDefition,以及动态修改Bean的作用。Spring主要有两种后处理器
    • BeanFactoryPostprocessor:Bean工厂后处理器,(执行时机)在BeanDefinitionMap填充完毕,Bean实例化之前执行
    • BeanPostProcessor:Bean后处理器,(执行时机)一般在Bean实例化后,填充到单例池singletonObjects之前执行

Bean工厂后处理器-BeanFactoryPostProcessor

  • BeanFactoryPostProcessor是一个接口规范,实现该接口的类只要交由Spring容器管理(即在配置文件中注册该类称为Bean对象)的话,那么Spring就会回调该接口的方法,用于对BeanDefition注册和修改功能
  • BeanFactoryPostProcessor定义如下
    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;@FunctionalInterface
      public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
      }
      
修改beanDefinition对象
  • 创建一个实现类(修改beanDefinition对象

    • package com.example.PostProcessor;import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("beanDefinitionMap填充完毕后会回调该方法");// todo 修改Map集合中的BeanDefinition对象BeanDefinition userService = beanFactory.getBeanDefinition("userService");userService.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");}
      }
      
  • 测试类

    • package com.example.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;
      public class TestApplicationContext {public static void main(String[] args)  {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println(context.getBean("userService"));}
      }
      
  • 运行结果如下

    • 显然bean对应的类被改变了 
添加beanDefiniton对象
方法一
  • 创建一个类(添加beanDefiniton对象
    • package com.example.PostProcessor;import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.beans.factory.support.DefaultListableBeanFactory;
      import org.springframework.beans.factory.support.RootBeanDefinition;public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// todo 向Map集合中添加一个BeanDefinition对象,即在配置文件中没有注册// 创建一个新的beanDefinition对象BeanDefinition beanDefinition = new RootBeanDefinition();// 设置bean对应的类beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;// 添加该beanDefinition对象listableBeanFactory.registerBeanDefinition("UserDAO", beanDefinition);}
      }
      

      在配置文件中没有配置UserDAO了

  • 测试类

    • package com.example.Test;import com.example.DAO.Impl.UserDAOImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestApplicationContext {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println(context.getBean(UserDAOImpl.class));}
      }
      
  • 运行结果

                beanDefinition对象成功添加


方法二
  • Spring提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作
    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //package org.springframework.beans.factory.support;import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
      }
      
  • 创建一个类实现后处理器BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor(记得将该类注册到Spring容器中)

    • package com.example.PostProcessor;import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.beans.factory.support.BeanDefinitionRegistry;
      import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
      import org.springframework.beans.factory.support.DefaultListableBeanFactory;
      import org.springframework.beans.factory.support.RootBeanDefinition;public class MyBeanFactoryPostProcessor02 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 注册beanDefinitionBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");registry.registerBeanDefinition("UserDAO", beanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
      }
      

      实现添加beanDefiniton就会简单很多

  • 测试类

    • package com.example.Test;import com.example.DAO.Impl.UserDAOImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestApplicationContext {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println(context.getBean(UserDAOImpl.class));}
      }
      
  • 运行结果如下

完整流程图 

        
 


自定义@Component
  • 案例
    • 使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描
  • 要求
    • 自定义@MyComponent注解,使用在类上
    • 使用资料中提供好的包扫描工具BaseClassScanUtils完成指定包的类扫描
      • 工具类链接如下
      • https://hkm-web.oss-cn-beijing.aliyuncs.com/Utils
    • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析最终被Spring管理
  • 具体代码如下
    • 注解类
      • package com.example.Anno;import java.lang.annotation.ElementType;
        import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
        import java.lang.annotation.Target;@Target(ElementType.TYPE) // 设该注解的使用范围
        @Retention(RetentionPolicy.RUNTIME) // 设置该注解运行期间可见
        public @interface MyComponent {String value(); //用于设置注解的值
        }
        
    • 工具类

      • package com.example.Utils;import com.example.Anno.MyComponent;
        import org.springframework.core.io.Resource;
        import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
        import org.springframework.core.io.support.ResourcePatternResolver;
        import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
        import org.springframework.core.type.classreading.MetadataReader;
        import org.springframework.core.type.classreading.MetadataReaderFactory;
        import org.springframework.util.ClassUtils;import java.util.HashMap;
        import java.util.Map;public class BaseClassScanUtils {//设置资源规则private static final String RESOURCE_PATTERN = "/**/*.class";public static Map<String, Class> scanMyComponentAnnotation(String basePackage) {//创建容器存储使用了指定注解的Bean字节码对象Map<String, Class> annotationClassMap = new HashMap<String, Class>();//spring工具类,可以获取指定路径下的全部类ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();try {String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN;Resource[] resources = resourcePatternResolver.getResources(pattern);//MetadataReader 的工厂类MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);for (Resource resource : resources) {//用于读取类信息MetadataReader reader = refractory.getMetadataReader(resource);//扫描到的classString classname = reader.getClassMetadata().getClassName();Class<?> clazz = Class.forName(classname);//判断是否属于指定的注解类型if(clazz.isAnnotationPresent(MyComponent.class)){//获得注解对象MyComponent annotation = clazz.getAnnotation(MyComponent.class);//获得属value属性值String beanName = annotation.value();//判断是否为""if(beanName!=null&&!beanName.equals("")){//存储到Map中去annotationClassMap.put(beanName,clazz);continue;}//如果没有为"",那就把当前类的类名作为beanNameannotationClassMap.put(clazz.getSimpleName(),clazz);}}} catch (Exception exception) {}return annotationClassMap;}public static void main(String[] args) {Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.itheima");System.out.println(stringClassMap);}
        }
        
    • 使用注解来注册为Bean对象的类

      • package com.example.Beans;import com.example.Anno.MyComponent;@MyComponent("otherBean")
        public class otherBeans {
        }
        

        在配置文件中没有配置该类作为bean对象

    • 后工厂处理器类(该类要交给Spring容器管理

      • package com.example.PostProcessor;import com.example.Utils.BaseClassScanUtils;
        import org.springframework.beans.BeansException;
        import org.springframework.beans.factory.config.BeanDefinition;
        import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
        import org.springframework.beans.factory.support.BeanDefinitionRegistry;
        import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
        import org.springframework.beans.factory.support.RootBeanDefinition;import java.util.Map;public class MyComponentBeanFactoryProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 通过工具去扫描指定包及其子包下的所有类,收集使用@MyComponent注解的类,放在Map集合中Map<String, Class> MyComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.example");// 遍历Map,组装BeanDefinition进行注册MyComponentAnnotationMap.forEach((beanName,clazz)->{// 获取beanClassNameString beanClassName = clazz.getName();// 创建beanDefinitionBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(beanClassName);// 注册registry.registerBeanDefinition(beanName,beanDefinition);});}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
        }
        

        通过后工厂处理器类来将标记了自己创建的@MyComponent注解的类创建为beanDefinition对象后添加到beanDefinitionMap集合中。

    • 测试类

      • package com.example.Test;import com.example.Beans.otherBeans;
        import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestApplicationContext {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println(context.getBean(otherBeans.class));}
        }
        
    • 运行结果


      •  

      • 运行成功~

  • 使用注解注册bean的原理

    • 最主要是通过Bean工厂后处理器进行实现的,通过工具类获取到添加了注解的类的集合后,在后处理器中,对扫描结果进行遍历,然后生成对对应的beanDefinition对象后,注册到beanDefinitonMap集合后即可。

相关文章:

Spring的后处理器-BeanFactoryPostprocessor

目录 Spring后处理器 Bean工厂后处理器-BeanFactoryPostProcessor 修改beanDefinition对象 添加beanDefiniton对象 方法一 方法二 自定义Component Spring后处理器 Spring后处理器是Spring对外开放的重要拓展点&#xff08;让我们可以用添加自己的逻辑&#xff09;&…...

Flutter 必备知识点

Flutter 升级 确保在项目根目录下&#xff08;含有 pubspec.yaml 的文件夹&#xff09; 在命令行中输入命令&#xff1a; flutter channel输出&#xff1a; Flutter channels: * mastermainbetastable这个可以在 pubspec.yaml 中查看&#xff1a; 切换分支也很简单&#xf…...

什么是FMEA(失效模式和影响分析)?

失效模式和影响分析&#xff08;FMEA&#xff09;是一个在开发阶段&#xff0c;用于确定产品或流程可能的风险和失败点的有条理的过程。FMEA团队会研究失效模式&#xff0c;也就是产品或流程中可能出错的地方&#xff0c;以及这些失效可能带来的影响&#xff08;如风险、损害、…...

Redis面试题(三)

文章目录 前言一、怎么理解 Redis 事务&#xff1f;二、Redis 事务相关的命令有哪几个&#xff1f;三、Redis key 的过期时间和永久有效分别怎么设置&#xff1f;四、Redis 如何做内存优化&#xff1f;五、Redis 回收进程如何工作的&#xff1f;六、 加锁机制总结 前言 怎么理…...

Python错误处理指南:优雅应对异常情况

目录 一. 异常是什么&#xff1f;二. 使用 try 和 except三. 捕获多个异常四. 使用 else五. 使用 finally六. 自定义异常七.Python中常见异常处理类型八.Python中常见异常处理实例九.异常处理最佳实践十.结论 当编写Python代码时&#xff0c;错误处理是一个重要的方面&#xff…...

MySQL学习笔记12

MySQL 查询语句&#xff1a; 1、查询五子句&#xff1a;&#xff08;重点&#xff09; mysql> select */字段列表 from 数据表名称 where 子句 group by 子句 having 子句 order by 子句 limit 子句; 1&#xff09;where 子句&#xff1b;条件筛选。 2&#xff09;group…...

【owt】构建m79的owt-client-native:使用vs2017

家里电脑换成了台式机,拷贝代码发现了三年前的owt客户端mfc工程。 不用下载第三方库,试着构建下: owt-client-native 我这里有3年前的代码,思索了下还是用vs2017构建吧: 重新构建一下 选用x86 的 vs2017 vs的命令行控制台 cls可以清理屏幕 之前构建过vs2022的webrtc原版 …...

Cpp/Qt-day020918Qt

目录 完善登录框 点击登录按钮后&#xff0c;判断账号&#xff08;admin&#xff09;和密码&#xff08;123456&#xff09;是否一致&#xff0c;如果匹配失败&#xff0c;则弹出错误对话框&#xff0c;文本内容“账号密码不匹配&#xff0c;是否重新登录”&#xff0c;给定两…...

Spring面试题10:Spring的XMLBeanFactory怎么使用

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring的XMLBeanFactory怎么使用 XmlBeanFactory是Spring框架中的一个实现类,它是BeanFactory接口的一个具体实现。XmlBeanFactory的主要作用是通…...

自定义数据类型

前言&#xff1a;小伙伴们又见面啦&#xff0c;今天这篇文章&#xff0c;我们来谈谈几种自定义数据类型。 目录 一.都有哪些自定义数据类型 二.结构体 结构体内存对齐 1.如何对齐 2.为什么要对齐 3.节省空间和提升效率的方法 &#xff08;1&#xff09;让占用空间小的成员…...

产品团队的需求验证和确认

需求核实过程是确保软件满足特定的规格要求&#xff0c;而验证则侧重于软件是否达到了最终用户的期望和需求。 如果你正在开发一种医疗产品&#xff0c;这种区别也可能在法规和标准中有所体现&#xff0c;例如&#xff1a; 820.30(f)&#xff1a;设计验证应确认设计的成果符合…...

【JVM】类加载的过程

文章目录 类的生命周期加载验证准备解析初始化简要概括 类的生命周期 一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期将会经历加载 &#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xf…...

Golang 结构化日志包 log/slog 详解(四):分组、上下文和属性值类型

上一篇文章讲解了 log/slog 包中的自定义日志属性字段和日志级别&#xff0c;本文讲解下分组、上下文和属性值类型 分组输出 slog 支持将字段放在组中并且可以给分组指定名称。如何展示分组的内容&#xff0c;取决于使用的 handler&#xff0c;例如 TextHandler 使用点号分隔…...

小白学Python:提取Word中的所有图片,只需要1行代码

#python# 大家好&#xff0c;这里是程序员晚枫&#xff0c;全网同名。 最近在小破站账号&#xff1a;Python自动化办公社区更新一套课程&#xff1a;给小白的《50讲Python自动化办公》 在课程群里&#xff0c;看到学员自己开发了一个功能&#xff1a;从word里提取图片。这个…...

pip修改位于用户目录下的缓存目录

默认 pip 缓存目录&#xff1a; Windows: C:\Users\${用户名}\AppData\Local\pip\cache Linux: ~/.cache/pip 一、修改方式 1.命令方式 pip config set global.cache-dir "D:\kwok\data\pip-cache" 2.配置文件方式 ① Windows&#xff1a; C:\Users\${用…...

更新、修改

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法: update 表名 列名该列新值, 列名该列新值, ... where 记录匹配条件; 说明&#xff1a;update 更新、修改 set 设置 …...

山西电力市场日前价格预测【2023-09-25】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-09-25&#xff09;山西电力市场全天平均日前电价为442.30元/MWh。其中&#xff0c;最高日前电价为720.46元/MWh&#xff0c;预计出现在19: 00。最低日前电价为276.06元/MWh&#xff0c;预计…...

从collections库的Counter类看items()方法和enumerate()方法

下面的代码是针对文件的词频统计&#xff0c;使用了collections库及其Counter类 import collections def count_word_frequency(text): words text.lower().split() word_counts collections.Counter(words) return word_counts def count_fileword_frequency(fi…...

2023-09-24 LeetCode每日一题(LRU 缓存)

2023-09-24每日一题 一、题目编号 146. LRU 缓存二、题目链接 点击跳转到题目位置 三、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存i…...

《计算机视觉中的多视图几何》笔记(10)

10 3D Reconstruction of Cameras and Structure 本章主要描述了如何利用2张图片来恢复相机的参数以及物体在三维空间中的形状。 文章目录 10 3D Reconstruction of Cameras and Structure10.1 Outline of reconstruction method10.2 Reconstruction ambiguity10.3 The proje…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

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

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...