Spring中常见的Bean后处理器

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,那么单例池中不存在对应类型的对象时会报错

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

运动轨迹仿真

重型运载火箭轨迹/总体参数一体化优化方法 硬核推导火箭运动方程,并用python仿真实现 rocket-simulation:MATLAB-火箭仿真软件 MatRockSim:Matlab 火箭飞行模拟器 【开源】飞鹰一号探空火箭——箭体设计、制造回顾与仿真对比 偏航角,滚动角&#xf…

基于双闭环PI的SMO无速度控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于双闭环PI的SMO无速度控制系统simulink建模与仿真,基于双闭环PI的SMO无速度控制系统主要由两个闭环组成:一个是电流环,另一个是速度环。…

2024深入评测CleanMyMac X4.14.6破解版新的功能

随着时间的推移,我们的Mac电脑往往会变得越来越慢,存储空间变得越来越紧张,这时候一个优秀的清理工具就显得尤为重要。作为一款备受好评的Mac清理工具,它能够为你的Mac带来全方位的清理和优化。在本文中,我们将深入评测…

中科驭数与宽睿科技达成战略合作,共筑超低时延软硬一体技术底座

近日,中科驭数(北京)科技有限公司(简称“中科驭数”)和上海宽睿信息科技有限责任公司(简称“宽睿科技”)完成战略合作协议签署。双方将结合各自在超低时延软硬件领域的深厚业务积累和技术产品优…

晶振的起振温度对电子设备的影响

晶振,作为电子设备中的关键元件,其性能参数对设备的稳定性和可靠性具有重要影响。其中,晶振的起振温度是决定其工作性能的重要因素之一。晶发电子将探讨晶振起振温度对电子设备的影响以及如何应对这些影响。 首先,我们要了解什么…

2023/12/26中断作业

成果图&#xff1a; 代码&#xff1a; 函数层 key_it.c #include "key_init.h" void key1_it_config() { //RCC时钟RCC->MP_AHB4ENSETR |(0X1<<5);//设置PF9管脚为输入GPIOF->MODER &(~(0x3<<18));//设置PF9管脚为exti9输入EXTI->EXTI…

减小PAPR——DFT扩频

文章目录 前言一、DFT 扩频原理二、MATLAB 仿真1、核心代码2、仿真结果①、4QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PAPR 性能②、16QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PAPR 性能③、64QAM 调制时 IFDMA、LFDMA 和 OFDMA 的 DFT 扩频技术的 PA…

如何在Photoshop中创建色彩鲜艳的文本效果

如何在 Photoshop 中制作霓虹灯 1. 如何创建背景 步骤 1 学习如何在 Photoshop 中制作霓虹灯文本的第一步是背景。创建一个新的 1160 x 750 像素文档&#xff0c;并将分辨率设置为 300。 转到"文件">"嵌入位置"&#xff0c;然后打开"垃圾灰色砖…

tensorrt环境安装-可用于深度学习模型加速推理

安装python环境 在anaconda的命令行中输入conda create --name py38 python3.8 安装python环境 然后安装深度学习框架pytorch环境 Previous PyTorch Versions | PyTorch 在这里面选择合适的环境 conda install pytorch1.8.0 torchvision0.9.0 torchaudio0.8.0 cudatoolki…

汽车项目管理

项目节点&#xff1a; MR (Management Review)——管理层评审 KO (Kick Off)——项目正式启动 SI (Strategy Intent)——战略意图 SC (Strategy Confirmation)——战略确认 PA (Program Approval)——项目批准 PR (Product Readiness)——产品就绪 VP (Verification Prototype)…

kubernetes -pod 实践

一、资源与对象 1、pod 容器都是由镜像启动的,但在容器外面会包裹通过Pod将容器包裹起来这个是K8s的概念,在这个Pod里面可以有一个或多个容器,那这个Pod的有什么特征呢 Pod里的所有容器都会调度在同一个节点上运行0。Pod中的所有容器会共享同一网络,它们有一个唯一的IP,…

leetcode 75. 颜色分类(medium)(优质解法)

链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 代码&#xff1a; class Solution {public void sortColors(int[] nums) {int left-1,rightnums.length,i0;while(i<right){if(nums[i]0){left;swap(nums,left,i);i;}else if(nums…

大师计划1.0 - log2 CRTO笔记

CRTOⅠ笔记 log2 这个笔记是我在2023年11月23日-12月22日中&#xff0c;学习CRTO所做的一些笔记。 事实上TryHackMe的路径和htb学院包含了许多CRTO的知识并且甚至还超出了CRTO&#xff08;CS除外&#xff09;&#xff0c;所以很多东西在THM和htb学院学过&#xff0c;这次CRTO等…

LLM应用于MPC

现有的基于学习的自动驾驶系统&#xff08;AD&#xff09;在理解高级信息和提供可解释性方面存在挑战。为了解决这些问题&#xff0c;这项工作采用LLM作为复杂AD场景的决策组件。作者设计了认知途径&#xff08;cognitive pathway&#xff09;来实现LLM的综合推理&#xff0c;并…

软件接口测试是什么?怎么测?

软件测试是一条超级长的跑道&#xff0c;最好分阶段来跑&#xff1a;先入行&#xff0c;后精通。网上能看到很多软件测试的帖子&#xff0c;但能够准确分类详细介绍的并不多。正好最近有时间&#xff0c;就把我所了解的软件测试做一个小小总结&#xff0c;对你有帮助的话&#…

【100个Cocos实例】环形ScrollView的实现方法

引言 Cocos中环形ScrollView的实现 大家好&#xff0c;今天是圣诞节&#xff0c;又是寒冷的一天。 在游戏开发中经常需要用到ScrollView去实现滚动的列表。 他通常包括垂直方向和水平方向两个选择。 本文将介绍一下ScrollView环形方向的实现。 本文源工程可在文末阅读原文…

ServletContext对象和ServletConfig对象

Servlet几个重要的类的关系图 ServletContext对象 问题&#xff1a; Request解决了一次请求内的数据共享问题&#xff0c;session解决了用户不同请求的数据共享问题&#xff0c;那么不同的用户的数据共享该怎么办呢&#xff1f; 解决&#xff1a;使用ServletContext对象 作…

关键字:extends关键字

在 Java 中&#xff0c;extends 是一个关键字&#xff0c;用于表示继承关系。当一个类使用 extends 关键字时&#xff0c;它表示该类是一个子类&#xff0c;并且继承了父类的属性和方法。 以下是 extends 关键字的解析&#xff1a; 语法&#xff1a; 描述&#xff1a; ChildC…

二分查找——OJ题(二)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、点名1、题目讲解2、算法原理3、代码实现 二、搜索旋转排序数组中的最⼩值1、题目讲解2、算…

Unity向Web服务器上传和下载图片

Unity向Web服务器上传和下载图片 如果本片有看不懂的请查看我上篇文章&#xff1a;[Unity与Web服务器Post&#xff0c;Get](https://blog.csdn.net/qq_42194657/article/details/103031573)一、上传和下载图片1.在Unity中创建一个RawImage并在WebManager.cs脚本中添加一个Textu…