Spring中常见的Bean后处理器

news2024/11/18 15:44:26

Bean后处理器的作用:为Bean生命周期各个阶段提供扩展。接下来我们查看一个案例

public class TestBeanPostProcessor {
    public static void main(String[] args) {
        //该容器不存在任何Spring中的bean对象,是一个干净的容器,且提供了正常容器中的refresh方法,方便我们测试
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        context.refresh();//去执行BeanFactory后处理器,添加Bean后处理器,初始化所有单例bean

        context.close();

    }
}

而Bean1与Bean2类什么也没有编写,主要是Bean3中存在一些注解

public class Bean3 {
    private Bean1 bean1;

    @Autowired
    public void setBean1(Bean1 bean1) {
        System.out.println("@Autowired注解生效");
        this.bean1 = bean1;
    }

    private Bean2 bean2;

    @Resource
    public void setBean2(Bean2 bean2) {
        System.out.println("@Resource注解生效");
        this.bean2 = bean2;
    }

    private String home;

    @Autowired
    private void setHome(@Value("${JAVA_HOME}") String home) {
        System.out.println("@Value注解生效");
        this.home = home;
    }

    @PostConstruct
    private void init(){
        System.out.println("初始化注解生效");
    }

    @PreDestroy
    private void destroy(){
        System.out.println("销毁注解生效");
    }
}

我们执行后发现结果如下

20:57:03.786 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@4361bd48
20:57:03.811 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
20:57:03.827 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
20:57:03.827 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
20:57:03.857 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@4361bd48, started on Mon Dec 25 20:57:03 CST 2023

没有输出任何的打印语句,因此我们可以得知注解都没有生效,接下来我们测试添加Spring中常用的Bean后处理器后结果会有什么不同

添加图中的代码,红框中的第一行代码是修改beanFactory的自动装配的解析器,修改过后可以获取@Value中的属性,这个东西我会在后续的文章中解释

添加完这两个Bean后处理器之后再次执行后控制台信息如下

21:21:19.937 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@2401f4c3
21:21:19.955 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
21:21:19.969 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
21:21:19.976 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
21:21:19.986 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
21:21:20.006 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
@Resource注解生效
@Autowired注解生效
21:21:20.035 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
@Value注解生效
D:\Java
初始化注解生效
21:21:20.047 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@2401f4c3, started on Mon Dec 25 21:21:19 CST 2023
销毁注解生效

另一个需要注意的是,在多个Bean后处理器时,Spring会对Bean后处理器进行一个排序,在不更改排序规则前提下,优先解析@Resource注解再解析@Autowired注解

接下来我们查看另一种Bean后处理器,首先给出Bean4中的代码

/**
 * 会从配置文件中获取java.home与java.version两个k得到v注入对象中的属性
 */
@ConfigurationProperties(prefix = "java")
public class Bean4 {
    private String home;
    private String version;

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return "Bean4{" +
                "home='" + home + '\'' +
                ", version='" + version + '\'' +
                '}';
    }
}

我们测试之前的两个Bean后处理器能否获取到环境中的信息并将值赋值给类中的属性,运行结果如下

可以看到无法之前添加的Bean后处理器无法处理该注解,因此我们需要再次添加另一个Bean后处理器,也就是下图中红框中的内容

执行结果如下

接下来我们分析@Autowired是如何解析的,新建一个类我们自己手动调用Bean后处理器中的注入部分的方法

public class TestAutowiredBeanPostProcessor {
    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //这里使用registerSingleton方式是省去了bean的声明周期的流程,直接创建一个对象存放在单例池中。
        beanFactory.registerSingleton("bean1", new Bean1());
        beanFactory.registerSingleton("bean2", new Bean2());

        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        //探究该Bean后处理器是如何解析Autowired注解的
        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        //该处理器要注入对象,对象的获取来自于beanFactory因此,需要给处理器BeanFactory属性
        processor.setBeanFactory(beanFactory);

        Bean3 bean3 = new Bean3();
        System.out.println(bean3);//此时注解一定不会被执行
        //暴力反射
        Method method = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        method.setAccessible(true);
        //得到该类中有多少需要被解析的注解以及注解信息
        InjectionMetadata metadata = (InjectionMetadata) method.invoke(processor, "bean3", Bean3.class, null);

        metadata.inject(bean3,"bean3",null);
        System.out.println(bean3);
    }
}

上述代码中的metadata对象存储的信息如下

程序直接结果如下

Bean3{bean1=null, bean2=null, home='null'}
@Autowired注解生效
@Value注解生效
Bean3{bean1=com.zmt.test3.Bean1@3fee9989, bean2=null, home='${JAVA_HOME}'}

由于bean2上注解添加的是@Resource注解,因此不会被填充到bean3当中,那么接下来我们讲bean2字段上添加注解修@Autowired的同时注释掉setBean2方法上的@Resource注解,然后通过代码查看@Autowired注解是如何通过类型注入的

public class TestAutowiredBeanPostProcessor {
    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //这里使用registerSingleton方式是省去了bean的声明周期的流程,直接创建一个对象存放在单例池中。
        beanFactory.registerSingleton("bean1", new Bean1());
        beanFactory.registerSingleton("bean2", new Bean2());

        //inject方法中如何通过类型获取值
        //如果是通过在字段上添加的注解,先获取对应的字段对象
        Field bean2 = Bean3.class.getDeclaredField("bean2");
        //Spring会将获取到的字段封装成如下对象
        DependencyDescriptor dd2 = new DependencyDescriptor(bean2, false);
        //封装结束后inject内部会接着调用如下方法,根据字段对象获取到字段对象的类类型然后从单例池中获取到相同类型的对象
        Object o = beanFactory.doResolveDependency(dd2, null, null, null);
        System.out.println(o);

        //如果注解添加在方法上
        Method setBean1 = Bean3.class.getDeclaredMethod("setBean1", Bean1.class);
        DependencyDescriptor dd1 = new DependencyDescriptor(new MethodParameter(setBean1, 0), false);
        Object o1 = beanFactory.doResolveDependency(dd1, null, null, null);
        System.out.println(o1);
    }
}

可以看到成功获取到了bean1与bean2对象,然后通过反射的方法将值set到bean3的属性当中即可,需要注意的是,在创建DependencyDescriptor时,第二个参数为false的意思如果单例池中找不到对应的类型时不报错,如果为true,那么单例池中不存在对应类型的对象时会报错

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

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

相关文章

<JavaEE> 协议格式 -- 传输层协议 TCP

目录 一、TCP协议格式长啥样? 二、TCP协议属性解释 1)源端口号/目的端口号 2)序号/确认序号 3)TCP报头长度 4)保留位 5)标志位 6)窗口大小 7)校验和 8)紧急指针…

Oracle查询重复数据取第二行,好用来删除重复数据

Oracle查询重复数据取第二行,好用来删除重复数据 SELECT * FROM ( SELECT e.* , ROW_NUMBER() over(PARTITION BY product_category_id,model_size_id ORDER BY product_category_id,model_size_id) rn FROM equ_check_rules e ) s WHERE rn 2;

OSPF单区域配置-新版(11)

目录 整体拓扑 操作步骤 1.基本配置 1.1 配置R1的IP 1.2 配置R2的IP 1.3 配置R3的IP 1.4 配置PC-1的IP地址 1.5 配置PC-2的IP地址 1.6 配置PC-3的IP地址 1.7 检测R1直连链路连通性 1.8 检测R3直连链路连通性 1.9 检测R2直连链路连通性 2. 部署单区域OSPF网络 2.1…

php 不加后缀访问

实现不带后缀访问php文件的方法:首先在htaccess文件中加入内容“RewriteRule ^(api/token) token.php [L]”;然后通过根目录下的“token.php”来接受“api/token”;最后修改配置文件。 考虑的做法有: HTTP重写技术,让…

初探大模型微调

目标:低成本微调大模型,拥有属于自己的AI助手。 一切的一切,都得益于LoRA、QLoRA微调方法,没有A100一样可以微调大模型(用3090 24G显存微调70亿参数的baichuan绰绰有余,甚至参数量小一点的模型3060也能跑&a…

基于电商场景的高并发RocketMQ实战-Broker写入读取流程性能优化总结、Broker基于Pull模式的主从复制原理

🌈🌈🌈🌈🌈🌈🌈🌈 【11来了】文章导读地址:点击查看文章导读! 🍁🍁🍁🍁🍁🍁&#x1f3…

Windows实现MySQL5.7主从复制(详细版)

使用免安装版本(官网下载地址) 在Windows上安装两种MySQL服务并同时开启服务 1.下载配置 打开解压文件所在位置,就新建一个配置文件my.ini。 2.主库安装 主库的my.ini配置文件如下: [mysqld] #设置主库端口,注意须是…

UDP信号多个电脑的信息传输测试、配置指南

最近要做一个东西,关于一个软件上得到的信号,如何通过连接的局域网,将数据传输出去。我没做过相关的东西,但是我想应该和软件连接数据库的过程大致是差不多的,就一个ip和一个端口号啥的。 一.问题思路 多个设备同时连…

释放创造力的终极工具——Adobe Photoshop 2022 Mac/win

作为全球最受欢迎的图像处理软件,Adobe Photoshop一直是专业设计师和摄影师的首选工具。而最新推出的Adobe Photoshop 2022更是在功能和性能上迈出了重要的一步,为用户提供了更强大、更便捷的创作体验。 首先,Adobe Photoshop 2022引入了许多…

html table可编辑表格数据实现删除

这里教大家使用纯html和js脚本结合实现删除表格数据 <!DOCTYPE html> <html> <head><style>table {border-collapse: collapse;width: 100%;}th, td {border: 1px solid black;padding: 8px;text-align: left;}</style> </head> <body…

5G阅信应用场景有哪些?

5G阅信的应用场景非常广泛&#xff0c;以下是一些常见的应用场景&#xff1a; 1.工业自动化&#xff1a;5G阅信可以连接各种工业设备和传感器&#xff0c;实现设备之间的实时通信和控制&#xff0c;提高生产效率和自动化水平。 2.物联网和智能家居&#xff1a;5G阅信可以连接各…

【每日一题】LeetCode206.反转链表

个人主页&#xff1a;白日依山璟 专栏&#xff1a;Java|数据结构与算法|每日一题 文章目录 1. 题目描述示例1示例2示例3提示 2. 思路3.代码 1. 题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例1 输入&#xff1a;head [1…

文件夹改名方法:文件夹随机重命名的实用技巧,轻松管理

在日常生活和工作中&#xff0c;会遇到大量的文件夹要处理和管理。方便查找或分类&#xff0c;要对文件夹进行重命名。如果手动一个个重命名不仅耗时&#xff0c;还容易出错。现在一起来看看云炫文件管理器如何批量随机重命名文件夹&#xff0c;掌握这些技巧能更加轻松地应对工…

idea自动注释

前言 保存一下自己的自动注释代码 idea自动注释 前言1 创建类时&#xff0c;自动生成注释2 在方法上使用快捷键生成注释3 使用方法4 效果图 1 创建类时&#xff0c;自动生成注释 如下&#xff1a; #if (${PACKAGE_NAME} && ${PACKAGE_NAME} ! "")package …

SParC数据集介绍

导语 SParC是Text-to-SQL领域的一个多轮查询数据集。本篇博客将对该数据集论文和数据格式进行简要介绍。 SParC数据集概述 SParC是一个跨领域的多轮Text-to-SQL数据集。它包含有4298个问题轮次&#xff0c;大约有12k的自然语言问句到SQL标注的Question-SQL对。这些问题来自于…

【Python终端报错】“python.exe: can‘t open file”【及解决方法】

一、问题描述 如下图&#xff0c;在PyCharm中使用自带的Python终端运行源代码文件时&#xff0c;提示出错&#xff1a; D:\Program Files\Python3.10.0\python.exe: can’t open file ‘D:\Desktop\Python Security Chapter 4\Whois’: [Errno 2] No such file or directory 翻…

Winserver上如何配置和开启NTP客户端进行时间同步

场景 Winserver 2012 服务器&#xff0c;需要与其它服务器保持时间一致。 已知NTP服务器的ip,在winserver 服务器上如何进行配置和开启。 注&#xff1a; 博客&#xff1a;霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客 实现 1、运行-输入 gpedit.msc 打开组策略管理器…

个性化定制的知识付费小程序,为用户提供个性化的知识服务,知识付费saas租户平台

明理信息科技知识付费saas租户平台 在当今数字化时代&#xff0c;知识付费已经成为一种趋势&#xff0c;越来越多的人愿意为有价值的知识付费。然而&#xff0c;公共知识付费平台虽然内容丰富&#xff0c;但难以满足个人或企业个性化的需求和品牌打造。同时&#xff0c;开发和…

c++学习笔记(13)-左值和右值

一、左值与右值 啥是左值和右值呢&#xff1f; 左值&#xff1a;在内存有确定存储地址、有变量名&#xff0c;表达式结束依然存在的值&#xff0c;简单来说左值就是非临时对象。 右值&#xff1a;就是在内存没有确定存储地址、没有变量名&#xff0c;表达式结束就会销毁的值&…

1764程控直流电源

1764程控直流电源 交流输入电压范围&#xff1a;100&#xff5e;242Vac 在自动测试环境中提供偏置和对部件或最终产品提供激励的理想设备 国产思仪电源 01 产品综述 1764程控直流电源是在自动测试环境中提供偏置和对部件或最终产品提供激励的理想设备。其广泛应用于民用测…