Springboot扩展点之SmartInstantiationAwareBeanPostProcessor

news2024/11/27 19:52:53

前言

这是Springboot扩展点系列的第5篇了,主要介绍一下SmartInstantiationAwareBeanPostProcessor扩展点的功能特性、和实现方式。SmartInstantiationAwareBeanPostProcessor与其他扩展点最明显的不同,就是在实际的业务开发场景中应用到的机会并不多,主要是在Spring内部应用,但是为什么还要了解呢?遇到能力强的人要学他三分,遇到优秀的应用模式,同样也应该学他三分,这便是我依然要花一些时间把他分享给大家的原因。

功能特性

如下图为SmartInstantiationAwareBeanPostProcessor扩展点的UML类图,可以看出SmartInstantiationAwareBeanPostProcessor继承了InstantiationAwareBeanPostProcessor接口,而InstantiationAwareBeanPostProcessor接口又继承了BeanPostProcessor,对于InstantiationAwareBeanPostProcessor和BeanPostProcessor接口的功能特性、实现方式示例、工作原理在Springboot扩展点之InstantiationAwareBeanPostProcessorSpringboot扩展点之BeanPostProcessor两篇文章中都分别作了详细的分享,有兴趣的小伙们可以移步收藏+关注,而在本篇文章中着重分享SmartInstantiationAwareBeanPostProcessor接口独有的扩展方法。

1、SmartInstantiationAwareBeanPostProcesso接口有三个扩展点,分别是predictBeanType()、determineCandidateConstructors()、getEarlyBeanReference();

2、predictBeanType()用于在Bean实例化前预测最终返回的Class类型,触发时机是在nstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()之前,如果不能预测,则返回null或正确的Class;如果预测一个错误的Class,那么程序就会报错了(举个例子:如果形参beanClass是Student.class,返回时改成了Teacher.class,报错是毫无疑问的;那么问题来了:这么预测的意义在哪?这一点我没有太明白,有知道的小伙伴告诉我一下哈);

3、determineCandidateConstructors()

决定使用哪个构造器构造Bean,如果不指定,默认为null,即bean的无参构造方法;

(感觉这个扩展点意义不大,实际上构造器分为两类:无参构造方法,有参数构造方法,无非有参数的构造方法参数至少一个以上,用哪种构造器来构造Bean我感觉区别不大,打个比方:用普通碗吃饭与用金碗吃饭,对一些人来说可能是有区别的,对我来说,吃饱就好了,什么碗我不在乎,哈哈,小伙们你觉得呢?)

4、getEarlyBeanReference()

获得提前暴露的bean引用,主要用于Spring循环依赖问题的解决,如果Spring中检测不到循环依赖,这个方法不会被调用;当存在Spring循环依赖这种情况时,会在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法触发执行之后执行;

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    //预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;
    default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
      return null;
   }
    //决定使用哪个构造器构造Bean,如果不指定,默认为null,即bean的无参构造方法;
   default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
         throws BeansException {

      return null;
   }
    //获得提前暴露的bean引用,主要用于Spring循环依赖问题的解决;
   default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
      return bean;
   }
}

实现方式

Student.java

定义一个Student类,然后注入一个Teacher类;

@Slf4j
@Component
public class Student {
    private String name="xiao ming";
    @Autowired
    private Teacher teacher;

    public Student() {
        log.info("----student的无参数构造方法被执行");
    }

    public Student(String name) {
        this.name = name;
        log.info("----student的有参数构造方法被执行");
    }

    public Student(Teacher teacher) {
        this.teacher = teacher;
        log.info("----student的有参数构造方法(teacher)被执行");
    }

    public Student(String name, Teacher teacher) {
        this.name = name;
        this.teacher = teacher;
        log.info("----student的有参数构造方法(name,teacher)被执行");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        log.info("----student中的setTeacher方法被调用");
        this.teacher = teacher;
    }
}

Teacher.java

定义一个Teacher类,然后给Teacher类注入一个Student类,这样Student类和Teacher类就形成了循环依赖,方便后面验验MySmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference执行情况;

@Component
@Slf4j
public class Teacher {
    private String name="li lao shi";
    @Autowired
    private Student student;
    public Teacher() {
        log.info("----teacher的无参数构造方法被执行");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        log.info("----teacher中的setStudent方法被调用");
        this.student = student;
    }
}

MySmartInstantiationAwareBeanPostProcessor

定义MySmartInstantiationAwareBeanPostProcessor类,实现SmartInstantiationAwareBeanPostProcessor接口的predictBeanType方法、determineCandidateConstructors方法、getEarlyBeanReference方法、postProcessBeforeInstantiation方法;

@Component
@Slf4j
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("student")) {
            log.info("----predictBeanType方法被执行," + beanName);
            return Student.class;
        }
        return null;
    }
    //student类里是有四个构造方法,这里可以选择实际是两个:
    //一个无参数的构造方法,另一个是形参数是Teacher类型的
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("student") ) {
            log.info("----determineCandidateConstructors方法被执行," + beanName);
            Constructor<?> constructor = beanClass.getConstructors()[3];
            Constructor<?>[] constructors={constructor};
            return constructors;
        }
        return null;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        if (beanName.equals("student") ) {
            log.info("----getEarlyBeanReference方法被执行," + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("student")) {
            log.info("----postProcessBeforeInstantiation方法被执行,beanName:"+beanName);
            return null;
        }
        return null;
    }




}

单元测试验证

 @Test
    public void test3(){
        log.info("----单元测试执行开始");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Teacher student = context.getBean(Teacher.class);
        log.info("student的实际ClassName是----:"+student.getClass().getName());
        log.info("----单元测试执行完毕");

    }

总结

以上内容就是Springboot的SmartInstantiationAwareBeanPostProcessor扩展点的全部内容,主要分享了功能特性和实现方式,之所以没有介绍其工作原理,是因为我发现,这个扩展点实际上很鸡肋,Spring的内部有使用,但是也很少,在实际业务开发中,很难用到,所以再长篇介绍其工作原理没有什么意义,然后就偷个赖啦(不要打我哦)。

完整的实现方式示例项目地址:https://gitcode.net/fox9916/fanfu-web.git

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

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

相关文章

机器学习框架sklearn之特征降维

目录特征降维概念特征选择过滤式①低方差特征过滤②相关系数③主成分分析特征降维 0维 标量 1维 向量 2维 矩阵 概念 降维是指在某些限定条件下&#xff0c;降低随机变量&#xff08;特征&#xff09;个数&#xff0c;得到一组“不相关”主变量的过程 注&#xff1a;正是…

微信小程序 java 医生预约挂号答疑问询系统

生预约答疑系统用户端是基于微信小程序端&#xff0c;医生和管理员是基于网页后端。本系统分为用户&#xff0c;管理员&#xff0c;医生三个角色&#xff0c;用户的主要功能是注册登陆小程序&#xff0c;查看新闻资讯&#xff0c;查看医生列表&#xff0c;预约医生&#xff0c;…

【unity细节】关于资源商店(Package Maneger)无法下载资源问题的解决

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于资源商店为何下载不了的问题⭐ 文章目录⭐关于资源商店为何下载不了的问题…

鸟哥的Linux私房菜读书笔记:文件系统的简单操作

磁盘与目录的容量 现在我们知道磁盘的整体数据实在superblock区块中,但是每个个别文件的容量则在inode当中记载的. 那在命令行下面该如何显示处这几个数据呢? df:列出文件系统的整体磁盘书用量du:评估文件系统的磁盘使用量(常用在推估目录所占容量)df先来说明一下范例一所输…

网络协议(四):网络互联模型、物理层、数据链路层

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 网络协议(三)&#xff1a;路由器原理及数据包传输过程 网络协议(四)&#xff1a;网络互联模型、物理层、数据链路层 目录一、网…

HER2靶向药物研发进展-销售数据-上市药品前景分析

HER2长期作为肿瘤领域的热门靶点之一&#xff0c;其原因是它在多部位、多种形式的癌症中均有异常的表达&#xff0c;据研究表明HER2除了在胃癌、胆道癌、胆管癌、乳腺癌、卵巢癌、结肠癌、膀胱癌、肺癌、子宫颈癌、子宫浆液性子宫内膜癌、头颈癌、食道癌中的异常表达还存在于多…

从0到0.1学习 maven(三:声明周期、插件、聚合与继承)

该文章为maven系列学习的第三篇&#xff0c;也是最后一篇 第一篇快速入口&#xff1a;从0到0.1学习 maven(一&#xff1a;概述及简单入门) 第二篇快速入口&#xff1a;从0到0.1学习 maven(二&#xff1a;坐标、依赖和仓库) 文章目录啥子叫生命周期生命周期详解clean生命周期def…

统计检验(一)// 方差分析

【应用案例】 检验不同组&#xff08;即不同收入者&#xff09;是否存在“品类满意度”显著差异。各组的满足度平均值如下&#xff1a; 【操作步骤】 方差分析的前提条件是各组总体方差没有显著差异。 第一步&#xff1a;方差同质性检验 原假设&#xff1a;没有差异。 结论…

接口测试入门,如何划分接口文档

1.首先最主要的就是要分析接口测试文档&#xff0c;每一个公司的测试文档都是不一样的。具体的就要根据自己公司的接口而定&#xff0c;里面缺少的内容自己需要与开发进行确认。 我认为一针对于测试而言的主要的接口测试文档应该包含的内容分为以下几个方面。 a.具体的一个业…

时间复杂度的计算(2023-02-10)

时间复杂度的计算 时间复杂度的计算分为三大类&#xff1a;一层循环、二层循环和多层循环。 一层循环 1.找出循环趟数t及每轮循环i的变化值 2.确立循环停止的条件 3.得出t与i之间的关系 4.联立两式&#xff0c;得出结果 eg: void fun(int n) {int i0;while (i*i*i<n)i;…

LeetCode刷题模版:292、295、297、299-301、303、304、309、310

目录 简介292. Nim 游戏295. 数据流的中位数297. 二叉树的序列化与反序列化【未理解】299. 猜数字游戏300. 最长递增子序列301. 删除无效的括号【未理解】303. 区域和检索 - 数组不可变304. 二维区域和检索 - 矩阵不可变309. 最佳买卖股票时机含冷冻期310. 最小高度树【未理解】…

测试开发,测试架构师为什么能拿50 60k呢需要掌握哪些技能呢

这篇文章是软件工程系列知识总结的第五篇&#xff0c;同样我会以自己的理解来阐述软件工程中关于架构设计相关的知识。相比于我们常见的研发架构师&#xff0c;测试架构师是近几年才出现的一个岗位&#xff0c;当然岗位title其实没有特殊的含义&#xff0c;在我看来测试架构师其…

产业互联网是对互联网的衍生和进化,也是一次重塑和再造

互联网并不仅仅只是充当撮合和中介的角色&#xff0c;它应当具备更多的功能和意义。只有这样&#xff0c;它的发展才能够真正全面和完善。产业互联网的衍生和出现&#xff0c;正是在互联网进化的基础之上出现的。这是我们看到之所以会有那么多的互联网玩家投身到产业互联网的浪…

FITC-PEG-FA,荧光素-聚乙二醇-叶酸,FA-PEG-FITC,实验室科研试剂,提供质量检测

FITC-PEG-FA&#xff0c;荧光素-聚乙二醇-叶酸 中文名称&#xff1a;荧光素-聚乙二醇-叶酸 英文名称&#xff1a;FITC-PEG-FA 英文别名&#xff1a;Fluorescein-PEG-Folic Acid 性状&#xff1a;基于不同的分子量&#xff0c;呈白色/类白色固体&#xff0c;或粘稠液体。 溶…

第九节 使用设备树实现RGB 灯驱动

通过上一小节的学习&#xff0c;我们已经能够编写简单的设备树节点&#xff0c;并且使用常用的of 函数从设备树中获取我们想要的节点资源。这一小节我们带领大家使用设备树编写一个简单的RGB 灯驱动程序&#xff0c;加深对设备树的理解。 实验说明 本节实验使用到STM32MP1 开…

使用gitlab ci/cd来发布一个.net 项目

gitlab runner的安装和基本使用:https://bear-coding.blog.csdn.net/article/details/120591711安装并给项目配置完gitlab runner后再操作后面步骤。实现目标&#xff1a;master分支代码有变更的时候自动构建build。当开发人员在gitlab上给项目打一个tag标签分支的时候自动触发…

4.5.4 LinkedList

文章目录1.特点2.常用方法3.练习:LinkedList测试1.特点 链表,两端效率高,底层就是链表实现的 List接口的实现类&#xff0c;底层的数据结构为链表&#xff0c;内存空间是不连续的 元素有下标&#xff0c;有序允许存放重复的元素在数据量较大的情况下&#xff0c;查询慢&am…

代码随想录NO39 |0-1背包问题理论基础 416.分割等和子集

0-1背包问题理论基础 分割等和子集1. 0-1背包问题理论基础(二维数组实现)2. 0-1背包问题理论基础 二&#xff08;一维数组实现&#xff09;1. 0-1背包问题理论基础(二维数组实现) 背包问题一般分为这几种&#xff1a; 0-1背包问题&#xff1a;有n件物品和一个最多能背重量为w…

51单片机15单片机 时钟芯片DS1302【更新中】

前言 现在流行的串行时钟电路很多&#xff0c;如DS1302、 DS1307、PCF8485等。这些电路的接口简单、价格低廉、使用方便&#xff0c;被广泛地采用。 本文介绍的实时时钟电路DS1302是DALLAS公司的一种具有涓细电流充电能力的电路主要特点是采用串行数据传输&#xff0c;可为掉电…

配置与管理FTP服务器

FTP的概念及作用 FTP( 文件传输协议 ) 是目前Internet上流行的数据传输方法之一。利用FTP协议&#xff0c;可以在FTP服务器和客户机之间进行双向传输&#xff0c;既可以把数据从FTP服务器上下载到本地客户机&#xff0c;又可以从客户机上传数据到远程FTP服务器。FTP最初与WWW服…