Spring中常见的BeanFactory后处理器

news2024/11/19 3:30:04

常见的BeanFacatory后处理器

先给出没有添加任何BeanFactory后处理器的测试代码

public class TestBeanFactoryPostProcessor {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }
}

在配置类中我们编写了如下信息

@Configuration
@ComponentScan("com.zmt.test5")
public class Config {

    @Bean
    public Bean2 bean2(){
        return new Bean2();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }
}

同时还有一个Bean1添加了@Component注解并且能够被扫描到,所以理论上来讲,我们可以观察到五个beanName,那么执行测试代码观察输出结果

可以看到,这里只输出了一个beanName,我们可以推测出其他注解没有生效,那么接下来我们将常用的BeanFactory后处理器也注册到BeanFactory后,观察输出结果

public class TestBeanFactoryPostProcessor {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        //添加BeanFactory后处理器
        context.registerBean(ConfigurationClassPostProcessor.class);//用来解析 @ComponentScan @Bean @Import @ImportResource注解
        context.registerBean(MapperScannerConfigurer.class,bd -> {
            bd.getPropertyValues().add("basePackage","com.zmt.test.mapper");
        });//扫描Mapper,相当于@MapperScan注解

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }
}

添加Spring提供的BeanFactory后处理器之后,可以正常将Bean对象添加到context容器当中了,执行结果如下

接下来我们模拟实现在BeanFactory后处理器当中具体如何解析这些注解。 

模拟实现组件扫描

首先是模拟实现@ComponentScan注解是如何扫描包,获取类资源的

public class TestBeanFactoryPostProcessor {
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        //模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解
        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
        if (componentScan != null) {
            for (String s : componentScan.basePackages()) {
                //将com.zmt.test5.bean转化格式为classpath*:com/zmt/test5/bean/**/*.class
                String path = "classpath*:"+s.replace(".", "/")+"/**/*.class";
                //创建出一个元数据读取工厂,用来读取类资源信息
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                //通过getResource方法获取到path中的所有类资源
                Resource[] resources = context.getResources(path);
                for (Resource resource : resources) {
                    //读取类资源信息
                    MetadataReader reader = factory.getMetadataReader(resource);
                    System.out.println("类名:"+reader.getClassMetadata());
                    System.out.println("是否添加了@Component注解:"+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
                    System.out.println("是否添加了@Component的派生注解:"+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
                }
            }
        }

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }
}

运行结果如下,可以正常识别类上是否添加了@Component注解或是派生注解

能够扫描到类上添加的注解之后,我们是需要将注解添加到BeanDefinitionMap当中去的,那么继续完善我们的测试方法

public class TestBeanFactoryPostProcessor {
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

        //模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解
        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
        if (componentScan != null) {
            for (String s : componentScan.basePackages()) {
                //将com.zmt.test5转化格式为classpath*:com/zmt/test5/**/*.class
                String path = "classpath*:" + s.replace(".", "/") + "/**/*.class";
                //创建出一个元数据读取工厂,用来读取类资源信息
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                //通过getResource方法获取到path中的所有类资源
                Resource[] resources = context.getResources(path);
                //创建Bean名称生成器
                AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                for (Resource resource : resources) {
                    //读取类资源信息
                    MetadataReader reader = factory.getMetadataReader(resource);
                    System.out.println("类名1:" + reader.getClassMetadata());
                    AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                    System.out.println("是否添加了@Component注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                    System.out.println("是否添加了@Component的派生注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                    if (annotationMetadata.hasAnnotation(Component.class.getName()) ||
                            annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                        //如果该类添加了注解,需要添加到BeanDefinitionMap当中去,生成BeanDefinition对象
                        AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName())
                                .getBeanDefinition();
                        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
                        //生成Bean名称
                        String name = generator.generateBeanName(bd,beanFactory);
                        System.out.println("name:"+name);
                        //将BeanDefinition注册到beanFactory
                        beanFactory.registerBeanDefinition(name,bd);
                    }
                }
            }
        }

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }
}

我们通过打断点查看beanFactory中是否将BeanDefinition信息注册到BeanDefinitionMap当中去,结果如下

至此已经实现了组件扫描,但是目前我们的实现是在容器初始化 [refresh()方法] 之前就做好了,我们应该将这些实现抽取到一个BeanFactory后处理器当中,等待refresh()方法回调,因此我们将这些实现代码放入一个组件扫描后处理器。

public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
    @Override //在执行context.refresh()方法时回调该方法
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String s : componentScan.basePackages()) {
                    //将com.zmt.test5转化格式为classpath*:com/zmt/test5/**/*.class
                    String path = "classpath*:" + s.replace(".", "/") + "/**/*.class";
                    //创建出一个元数据读取工厂,用来读取类资源信息
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    //通过getResource方法获取到path中的所有类资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    //创建Bean名称生成器
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        //读取类资源信息
                        MetadataReader reader = factory.getMetadataReader(resource);
                        System.out.println("类名1:" + reader.getClassMetadata());
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        System.out.println("是否添加了@Component注解:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println("是否添加了@Component的派生注解:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                        if (annotationMetadata.hasAnnotation(Component.class.getName()) ||
                                annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            //如果该类添加了注解,需要添加到BeanDefinitionMap当中去,生成BeanDefinition对象
                            AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory){
                                DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                                String name = generator.generateBeanName(bd,beanFactory);
                                System.out.println("name:"+name);
                                beanFactory.registerBeanDefinition(name,bd);
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

修改此时的测试代码,将我们自定义的BeanFactory后处理器注册到context当中 

public class TestBeanFactoryPostProcessor {
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        //模拟ConfigurationPostProcessor处理器中如何解析@ComponentScan注解
        context.registerBean(ComponentScanPostProcessor.class);

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }
}

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

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

相关文章

漏刻有时数据可视化Echarts组件开发(46)散点图颜色判断

series组件 series: [{name: Top 5,type: scatter,coordinateSystem: bmap,data: convertData(data.sort(function (a, b) {return b.value - a.value;}).slice(0, 6)),symbolSize: 20,encode: {value: 2},showEffectOn: render,rippleEffect: {brushType: stroke},label: {fo…

QuPath病理流程学习 ③ IHC、HE (WSI的处理)实战

示例数据 示例样本获取,里面有HE和IHC两种切片数据 Hamamatsu NDPI (cmu.edu) Cell detection — QuPath 0.5.0 documentation 在QuPath中,病理选择Brightfield H&E和Brightfield DAB代表了不同的染色方式。H&E代表了Hematoxylin and Eosin&am…

简化报表设计器Fastreport 中 TableObject 的工作

在 2024.1 更新之前,要添加行或列,您必须在属性面板中查找所需的属性并设置所需的值。如果您想要在表格末尾以外的位置插入行或列,则必须手动传输所有单元格值。此外,要传输值,需要打开编辑器,复制值&#…

[数据结构]树与二叉树的性质

文章目录 0.二叉树的形态和基本性质1.完全二叉树的叶子节点个数2.树的叶子节点个数3.线索二叉树4.树和森林和二叉树5.平衡二叉树的最少结点数6.树/二叉树/森林的转换 0.二叉树的形态和基本性质 一棵二叉树具有5中基本形态n个结点可以构造的二叉树种数: C2n-n/n1 一棵树 n个结点…

红队打靶练习:DIGITALWORLD.LOCAL: FALL

目录 信息收集 1、arp 2、netdiscover 3、nmap 4、nikto 5、whatweb 6、小结 目录探测 1、gobuster 2、dirsearch WEB 80端口 /test.php 文件包含漏洞 SSH登录 提权 get root and flag 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interfa…

Qt Creator可视化交互界面exe快速入门3

上一期介绍的通过Qt Creator的组件直接拖拽的方式完成了一个界面,这期介绍按钮的信号交互。 专有名称叫信号与槽 实现方法1: 鼠标右键选择转化为槽就会跳出这样的界面 选择第一个为单击信号。然后就会跳转到代码界面。多了on_pushButton_clicked()。 …

问题解决 | Ubuntu重启无法进入系统

Ubuntu18.04重启无法进入系统,重开后如图 一直在加载系统内核4.15.0-213-generic,无法加载 错误原因 原本的系统是Ubuntu16.04,使用命令升级到Ubuntu18.04版本,升级重启后,远程无法连接! 错误解决 第一步:进入GRUB…

模型量化 | Pytorch的模型量化基础

官方网站:Quantization — PyTorch 2.1 documentation Practical Quantization in PyTorch | PyTorch 量化简介 量化是指执行计算和存储的技术 位宽低于浮点精度的张量。量化模型 在张量上执行部分或全部操作,精度降低,而不是 全精度&#xf…

【网络安全 | 网络协议】结合Wireshark讲解IP协议

前言:IP协议传输过程与数据分片 当我们进行数据传输时,操作系统会创建一个 ICMP Echo Request 数据包,并在该数据包中包含要发送的目标 IP 地址。然后操作系统将数据包传递给网络协议栈,该数据包被封装成 IP 数据包。IP 数据包的…

SpringBoot3 整合Swagger

OpenAPI 3 与 Swagger Swagger 可以快速生成实时接口文档&#xff0c;方便前后开发人员进行协调沟通。遵循 OpenAPI 规范。 文档&#xff1a;https://springdoc.org/v2/ 1. OpenAPI 3 架构 2. 整合 导入场景 <dependency><groupId>org.springdoc</groupId>…

初见 Amazon Q

前言 如果今年要写一篇年终总结的话&#xff0c;生成式 Ai 一定是绕不过的一个话题&#xff0c;自从去年的 chatGPT 火爆全球后&#xff0c;今年各种生成式 Ai 的产品络绎不绝地出现大众视线&#xff0c;版本迭代的速度也是非常快&#xff0c;大家甚至开始在自己的生活和工作中…

【星海随笔】网络运维

[rootlocalhost ~]# source admin-openrcRabbitMQ 工作机理 1.客户端连接到消息队列服务器&#xff0c;打开一个channel。 2.客户端声明一个exchange&#xff0c;并设置相关属性。 3.客户端声明一个queue&#xff0c;并设置相关属性。 4.客户端使用routing key&#xff0c;在ex…

教程分享:如何将音频生成二维码?

音频二维码正在各行各业发挥着重要的作用。比如出版图书中的发音讲解二维码&#xff1b;艺术展博物馆展览中的音频讲解二维码&#xff1b;在线音乐教学通过音频二维码向学员提供教学资料&#xff1b;品牌在创意广告中使用音频二维码向客户提供定制二维码祝福…… 其实&#xf…

HTML---定位

目录 文章目录 一.定位属性概述 二.position 基础数值 三.z-index属性 网页元素透明度 练习 一.定位属性概述 HTML中的定位属性指的是用来控制HTML元素在页面中的位置和布局的属性&#xff0c;包括position、top、bottom、left和right等。 position属性指定了元素的定位方式&a…

Dynamic Wallpaper:打造个性化的 macOS 桌面体验

概述 在日常使用电脑的过程中&#xff0c;桌面背景往往是我们接触最频繁的元素之一。传统的静态壁纸已经无法满足用户对于个性化和创意的追求。于是&#xff0c;一款名为 "Dynamic Wallpaper" 的 macOS 上的动态壁纸软件应运而生。本文将详细介绍 Dynamic Wallpaper…

STM32 cubeMX 人体红外模块实验

本文代码使用HAL库。 文章目录 前言一、人体红外模块介绍工作原理&#xff1a; 二、人体红外原理图解读三、STM32 cubeMX配置红外模块四、代码编写总结 前言 实验开发板&#xff1a;STM32F051K8。所需软件&#xff1a;keil5 &#xff0c; cubeMX 。实验目的&#xff1a;了解 人…

【xdma】 pcie.bar设置

FPGA优质开源项目– PCIE通信 xdma 两者保持一致 FPGA开源项目 – PCIE I/O控制卡 xdma PCIe的XDMA应用 读写部分分为两种&#xff0c;一种是数据的读写&#xff0c;另一种是配置数据的读写&#xff0c;在数据读写部分&#xff0c;DMA通过MIG控制DDR完成数据读写。配置数…

C/C++ 函数指针

如果未提到函数指针&#xff0c;则对C或C函数的讨论将是不完整的。我们将大致介绍一下这个主题&#xff0c;将完整的介绍留给更高级的图书。与数据项相似&#xff0c;函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。通常&#xff0c;这些地址对用户而言&#…

CTF特训(一):ctfshow-RCE挑战

CTF特训(一)&#xff1a;ctfshow-RCE挑战 FLAG&#xff1a;可后来&#xff0c;除了梦以外的地方&#xff0c;我再也没有见过你 专研方向: 代码审计&#xff0c;PHP 每日emo&#xff1a;其实挺迷茫的&#xff0c;不知道该干什么,(骗你的) RCE挑战1 <?phperror_reporting(0)…

Leetcode算法系列| 6. Z 字形变换

目录 1.题目2.题解C# 解法一&#xff1a;利用二维矩阵模拟C# 解法二&#xff1a;压缩矩阵空间Python3 解法三&#xff1a;直接构造 1.题目 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING”…