Spring的后处理器-BeanFactoryPostprocessor

news2024/11/19 1:48:21

目录

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 {
          @Override
          public 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 {
          @Override
          public 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 {
          @Override
          public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
              // 注册beanDefinition
              BeanDefinition beanDefinition = new RootBeanDefinition();
              beanDefinition.setBeanClassName("com.example.DAO.Impl.UserDAOImpl");
              registry.registerBeanDefinition("UserDAO", beanDefinition);
          }
          @Override
          public 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);
                        //扫描到的class
                        String 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;
                            }
        
                            //如果没有为"",那就把当前类的类名作为beanName
                            annotationClassMap.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 {
            @Override
            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
                // 通过工具去扫描指定包及其子包下的所有类,收集使用@MyComponent注解的类,放在Map集合中
                Map<String, Class> MyComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.example");
                // 遍历Map,组装BeanDefinition进行注册
                MyComponentAnnotationMap.forEach((beanName,clazz)->{
                    // 获取beanClassName
                    String beanClassName = clazz.getName();
                    // 创建beanDefinition
                    BeanDefinition beanDefinition = new RootBeanDefinition();
                    beanDefinition.setBeanClassName(beanClassName);
                    // 注册
                    registry.registerBeanDefinition(beanName,beanDefinition);
                });
        
            }
        
            @Override
            public 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集合后即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1035849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 PyTorch 的计算机视觉简介 (4/6)

一、说明 在本单元中&#xff0c;我们将了解卷 积神经网络&#xff08;CNN&#xff09;&#xff0c;它是专门为 计算机视觉设计的。 多层卷积层允许我们从图像中提取某些图像模式&#xff0c;池化层&#xff0c;以及在 CIFAR-10上的表现。 二、多层 CNN 在上一个单元中&#xf…

拦截|篡改|伪造.NET类库中不限于public的类和方法

大家好&#xff0c;我是沙漠尽头的狼。 本文首发于Dotnet9&#xff0c;介绍使用Lib.Harmony库拦截第三方.NET库方法&#xff0c;达到不修改其源码并能实现修改方法逻辑、预期行为的效果&#xff0c;并且不限于只拦截public访问修饰的类及方法&#xff0c;行文目录&#xff1a;…

Mysql004:用户管理

前言&#xff1a;本章节讲解的是mysql中的用户管理&#xff0c;包括&#xff08;管理数据用户&#xff09;、&#xff08;控制数据库的访问权限&#xff09;。 目录 1. 查询用户 2. 创建用户 3. 修改用户密码 4. 删除用户 5. 权限控制 1. 查询用户 在mysql数据库中&#xff0…

P-GaN栅极HEMT开关瞬态分析中的动态栅极电容模型

标题&#xff1a;Dynamic Gate Capacitance Model for Switching Transient Analysis in P-GaN Gate HEMTs 摘要 在这项工作中&#xff0c;提出了一种用于P-GaN栅极HEMT的高效开关瞬态分析模型&#xff0c;该模型考虑了开关瞬态过程中的动态栅极电容CG(VDS, VGS)特性。同时&a…

【STM32教程】第五章 STM32的定时器

案例代码及相关资料下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1hsIibEmsB91xFclJd-YTYA?pwdjauj 提取码&#xff1a;jauj 1 定时器综述 1.1 定时器简介 TIM&#xff08;Timer&#xff09;定时器&#xff0c;最基本功能就是定时触发中断&#xff1…

python随手小练3

题目&#xff1a; 写出一个判断闰年的python代码&#xff1a; 闰年的条件&#xff1a; 如果N能够被4整除&#xff0c;并且不能被100整除&#xff0c;则是闰年 或者&#xff1a;N能被400整除&#xff0c;也是闰年 即&#xff1a;4年一润并且百年不润&#xff0c;每400年再润一…

前端第二课,HTML,alt,title,width/heigh,border,<a>超链接,target,tr,td,th

目录 一、title: &#x1f49b; ​二、alt&#x1f499; 三、width/heigh&#x1f49c; 四、border ❤️ 五、超链接&#x1f49a; 六、target &#x1f497; 七、tr&#x1f495; 八、td&#x1f498; 九、th&#x1f49e; 十、rowspan 一、title: &#x1f49b; 快…

漏刻有时数据可视化Echarts组件开发(29):工业图形动画

var nodes = [{nodeName: 新能源,value: [-10, 100],symbolSize: 50,symbol:image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3R…

【操作系统笔记四】高速缓存

CPU 高速缓存 存储器的分层结构&#xff1a; 问题&#xff1a;为什么这种存储器层次结构行之有效呢&#xff1f; 衡量 CPU 性能的两个指标&#xff1a; 响应时间&#xff08;或执行时间&#xff09;&#xff1a;执行一条指令平均时间 吞吐量&#xff0c;就是 1 秒内 CPU 可以…

ideal 同一项目启动多实列

点击service(如果没有:点击菜单栏&#xff1a;Views -> Tool Windows -> Services&#xff1b;中文对应&#xff1a;视图 -> 工具窗口 -> 服务&#xff1b;快捷键是Alt F8&#xff0c;但是本地快捷键可能冲突&#xff0c;并未成功。) 刚创建好的窗口是空白的&…

回归预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于RF-Adaboost随机森林结合…

Android 遍历界面所有的View

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、实践四、 推荐阅读 一、导读 我们…

基于QT实现发送http的get和post请求(post还可以实现上传文件),同时实现接收返回json数据,并对其进行解析

使用到中重要的类&#xff0c;做个简单的介绍 QNetworkAccessManager&#xff1a;这个类是QT帮我们封装好的工具类&#xff0c;主要可以用来发送Http请求 QNetworkReply&#xff1a;这个类主要用来监听发送的请求&#xff0c;并得到请求的响应结果 QHttpMultiPart&#xff1a;这…

RSD处理气象卫星数据——常用投影

李国春 气象卫星扫描刈幅宽覆盖范围广&#xff0c;在地球的不同位置可能需要不同的投影以便更好地表示这些观测数据。这与高分辨率的局地数据有很大不同&#xff0c;高分数据更倾向于用使用处理局地小范围的投影方式。本文选择性介绍几种RSD常用的适合低、中、高纬和极地地区的…

python+nodejs+php+springboot+vue 校园安全车辆人员出入安全管理系统

本校园安全管理系统共包含15个表:分别是表现评分信息表&#xff0c;车辆登记信息表&#xff0c;配置文件信息表&#xff0c;家校互动信息表&#xff0c;监控系统信息表&#xff0c;教师信息表&#xff0c;留言板信息表&#xff0c;校园资讯信息表&#xff0c;人员登记信息表&am…

2023-9-23 合并果子

题目链接&#xff1a;合并果子 #include <iostream> #include <algorithm> #include <queue>using namespace std;int main() {int n;cin >> n;priority_queue<int, vector<int>, greater<int>> heap;for(int i 0; i < n; i){in…

Spring Cloud版本选择

SpringCloud版本号由来 SpringCloud的版本号是根据英国伦敦地铁站的名字进行命名的&#xff0c;由地铁站名称字母A-Z依次类推表示发布迭代版本。 SpringCloud和SpringBoot版本对应关系 注意事项&#xff1a; 其实SpringBoot与SpringCloud需要版本对应&#xff0c;否则可能会造…

墓园导航系统:实现数字化陵园祭扫新模式

墓园导航系统&#xff1a;实现数字化陵园祭扫新模式 随着人口老龄化趋势的加剧&#xff0c;人们对墓地的需求逐渐增加。同时&#xff0c;由于很多墓园面积较大&#xff0c;环境复杂&#xff0c;很多家属在寻找亲人墓地时感到不便和困难。此外&#xff0c;传统墓园的管理和服务水…

论文研读-数据共享-大数据流分析中的共享执行技术

Shared Execution Techniques for Business Data Analytics over Big Data Streams 大数据流分析中的共享执行技术 1、摘要 2020年的一篇共享工作的论文&#xff1a;商业数据分析需要处理大量数据流&#xff0c;并创建物化视图以便给用户实时提供分析结果。物化每个查询&#x…

FPGA——UART串口通信

文章目录 前言一、UART通信协议1.1 通信格式2.2 MSB或LSB2.3 奇偶校验位2.4 UART传输速率 二、UART通信回环2.1 系统架构设计2.2 fsm_key2.3 baud2.4 sel_seg2.5 fifo2.6 uart_rx2.7 uart_tx2.8 top_uart2.9 发送模块时序分析2.10 接收模块的时序分析2.11 FIFO控制模块时序分析…