Springboot扩展点之SmartInstantiationAwareBeanPostProcessor
创始人
2024-05-25 03:11:39
0

前言

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

功能特性

如下图为SmartInstantiationAwareBeanPostProcessor扩展点的UML类图,可以看出SmartInstantiationAwareBeanPostProcessor继承了InstantiationAwareBeanPostProcessor接口,而InstantiationAwareBeanPostProcessor接口又继承了BeanPostProcessor,对于InstantiationAwareBeanPostProcessor和BeanPostProcessor接口的功能特性、实现方式示例、工作原理在Springboot扩展点之InstantiationAwareBeanPostProcessor和Springboot扩展点之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";@Autowiredprivate 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";@Autowiredprivate 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 {@Overridepublic Class predictBeanType(Class beanClass, String beanName) throws BeansException {if (beanName.equals("student")) {log.info("----predictBeanType方法被执行," + beanName);return Student.class;}return null;}//student类里是有四个构造方法,这里可以选择实际是两个://一个无参数的构造方法,另一个是形参数是Teacher类型的@Overridepublic 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;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {if (beanName.equals("student") ) {log.info("----getEarlyBeanReference方法被执行," + beanName);}return bean;}@Overridepublic Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {if (beanName.equals("student")) {log.info("----postProcessBeforeInstantiation方法被执行,beanName:"+beanName);return null;}return null;}}

单元测试验证

 @Testpublic 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

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...