21. Spring扩展点之推断构造方法

简介

spring自己本身有推断构造方法的逻辑,但同时也提供了扩展,SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors,实现该方法就可以自己定制获取哪个构造器的逻辑,该扩展点spring有一个默认的实现AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

本文主要分析的就是该默认的推断构造方法实现类

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)throws BeanCreationException {// lookup逻辑上节已经介绍过了,这里省略掉// 并发安全检查过滤掉Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {synchronized (this.candidateConstructorsCache) {candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {Constructor<?>[] rawCandidates;// 拿到所有的构造方法rawCandidates = beanClass.getDeclaredConstructors();// 记录的是所有加了@Autowrite注解的构造方法List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);// 记录加了@Autowrite注解required为true的构造方法,只能赋值一个Constructor<?> requiredConstructor = null;// 记录无参构造Constructor<?> defaultConstructor = null;int nonSyntheticConstructors = 0;// 遍历每个构造方法for (Constructor<?> candidate : rawCandidates) {// isSynthetic后面文章分析if (!candidate.isSynthetic()) {nonSyntheticConstructors++;}// 如果当前构造器加了@Autowired注解,那么ann就有值MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);// 当前构造方法上加了@Autowiredif (ann != null) {// 只能有一个Autowired的required为true,多了就报错if (requiredConstructor != null) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}// 获取required值boolean required = determineRequiredStatus(ann);if (required) {// 如果说required为true,那么就不允许出现有其它的@Autowired,为false也不行if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructors: " + candidates +". Found constructor with 'required' Autowired annotation: " +candidate);}// 记录唯一一个required为true的构造方法requiredConstructor = candidate;}// 记录@Autowired标记的构造器candidates.add(candidate);} else if (candidate.getParameterCount() == 0) {// 记录无参的构造方法,如果加了@Autowired,就不需要记录defaultConstructor = candidate;}// 有参数,但是没有添加@Autowired的构造器没有做判断}if (!candidates.isEmpty()) { // 存在@Autowiredif (requiredConstructor == null) { // 没有required为true的构造方法if (defaultConstructor != null) {// 没有required为true的情况下 无参构造与required为false一样的candidates.add(defaultConstructor);}}candidateConstructors = candidates.toArray(new Constructor<?>[0]);}// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {candidateConstructors = new Constructor<?>[] {rawCandidates[0]};}else {// 没有加@Autowired,构造器又不止一个,那么返回空,后面由spring经过算法去推断使用哪一个candidateConstructors = new Constructor<?>[0];}// 缓存起来this.candidateConstructorsCache.put(beanClass, candidateConstructors);}}}return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

上面就是默认提供的一个推断构造器扩展实现,大致总结下

1. 如果有一个构造器添加了@Autowired并且required值为true,那么就不能再出现@Autowired修饰的构造器
2. 如果没有required值为true的,那么添加了@Autowired与无参的构造器都返回,由spring根据算法去选择
3. 只有一个构造器,并且不是无参的,那么就直接返回这个构造器
4. 如果都没有加@Autowired,构造器又不止一个,那么返回空,由spring根据算法去选择哪个

测试

测试1 两个Autowired,一个为required = true

@Component
public class OrderBean {@Autowired(required = false)public OrderBean() {}@Autowiredpublic OrderBean(String orderName) {}
}报错
Error creating bean with name 'orderBean': Invalid autowire-marked constructors: [public com.shura.beans.OrderBean()]. Found constructor with 'required' Autowired annotation: public com.shura.beans.OrderBean(java.lang.String)

测试2 加了Autowired,那么会使用该构造器

@Component
public class OrderBean {public OrderBean() {}@Autowiredpublic OrderBean(UserBean userBean) {System.out.println("OrderBean 1");}
}执行输出
OrderBean 1

自定义

自定义一个推断构造器扩展,规则是优先使用有一个参数的构造器

@Component
public class DefaultConstructors implements SmartInstantiationAwareBeanPostProcessor {@Overridepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {if (declaredConstructor.getParameterCount() == 1) {// 有一个参数的构造器直接返回return new Constructor<?>[]{declaredConstructor};}}return null;}
}@Component
public class OrderBean {public OrderBean() {System.out.println("OrderBean 0");}public OrderBean(UserBean userBean) {System.out.println("OrderBean 1");}
}@ComponentScan({"com.shura"})
public class AppConfig {
}

启动类

public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(context.getBean("orderBean"));
}执行输出OrderBean 1
com.shura.beans.OrderBean@5cc7c2a6

总结

以上就是推断构造函数扩展点的讲解,下一节讲解扩展点没有推断出来构造器,那么spring又该怎么给我们选择构造器呢,其实跟@Bean的实例化非常相似,下节介绍


欢迎关注,学习不迷路!

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

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

相关文章

单元测试-java.lang.NullPointerException

报错信息 java.lang.NullPointerException 空指针异常 空对象引用 来源 对Controller层进行单元测试&#xff0c;解决完Spring上下文报错后继续报错。 解决 在测试方法执行前要为字段完成对象的注入&#xff0c;否则就报空指针异常。 测试例子 public class SysUserContr…

前端css粘性布局,顶部吸附效果(position: sticky)

sticky属性设置 /* 设置粘性布局 */ position: sticky; /* 拖动滚动条&#xff0c;当前元素超出文档0的位置时&#xff0c;触发定位效果&#xff08;同级元素位置不会受影响&#xff09; */ top: 0;页面初始效果 设置前&#xff08;滚动页面时&#xff0c;标签栏随页面滚动&a…

【深度学习】六大聚类算法快速了解

在机器学习中&#xff0c;无监督学习一直是我们追求的方向&#xff0c;而其中的聚类算法更是发现隐藏数据结构与知识的有效手段。目前如谷歌新闻等很多应用都将聚类算法作为主要的实现手段&#xff0c;它们能利用大量的未标注数据构建强大的主题聚类。本文从最基础的 K 均值聚类…

【二叉树进阶题目】236. 二叉树的最近公共祖先,JZ36 二叉搜索树与双向链表

二叉树进阶题目 236. 二叉树的最近公共祖先解题思路及实现思路一思路二 JZ36 二叉搜索树与双向链表描述解题思路及实现 236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个…

Axios 拦截器 请求拦截器 响应拦截器

请求拦截器 相当于一个关卡&#xff0c;如果满足条件就放行请求&#xff0c;不满足就拦截 响应拦截器 在处理结果之前&#xff0c;先对结果进行预处理&#xff0c;比如&#xff1a;对数据进行一下格式化的处理 全局请求拦截器 axios.interceptors.request.use(config > { /…

SeaTunnel及SeaTunnel Web部署指南(小白版)

现在你能搜索到的SeaTunnel的安装。部署基本都有坑&#xff0c;官网的文档也是见到到相当于没有&#xff0c;基本很难找到一个适合新手小白第一次上手就能成功安装部署的版本&#xff0c;于是就有了这个部署指南的分享&#xff0c;小主已经把可能遇到的坑都填过了&#xff0c;希…

Web前端—移动Web第五天(媒体查询、Bootstrap、综合案例-alloyTeam)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第五天01-媒体查询基本写法书写顺序案例-左侧隐藏媒体查询-完整写法关键词 / 逻辑操作符媒体类型媒体特性 媒体查询-外部CSS 02-Bootstrap简介使用步骤下载使用 栅格系统全局…

PTA 六度空间

“六度空间”理论又称作“六度分隔&#xff08;Six Degrees of Separation&#xff09;”理论。这个理论可以通俗地阐述为&#xff1a;“你和任何一个陌生人之间所间隔的人不会超过六个&#xff0c;也就是说&#xff0c;最多通过五个人你就能够认识任何一个陌生人。”如图1所示…

大白话DDD(DDD黑话终结者)

大白话DDD&#xff08;DDD黑话终结者&#xff09; 一、吐槽的话 相信听过DDD的人有很大一部分都不知道这玩意具体是干嘛的&#xff0c;甚至觉得它有那么一些虚无缥缈。原因之一是但凡讲DDD的&#xff0c;都是一堆特别高大上的概念&#xff0c;然后冠之以一堆让人看不懂的解释…

Python教程73:Pandas中一维数组Series学习

创建一维数据类型Series dataNone 要转化为Series的数据(也可用dict直接设置行索引) 若是标量则必须设置索引,该值会重复,来匹配索引的长度 indexNone 设置行索引 dtypeNone 设置数据类型(使用numpy数据类型) nameNone 设置Series的name属性 copyFalse 不复制 (当data为ndarray…

Centos中的解压和压缩指令

在CentOS 7系统中&#xff0c;可以使用多种命令进行文件压缩和解压缩操作。以下是常见的文件压缩和解压命令及其用法的详解&#xff1a; 1.tar&#xff1a;tar命令用于打包文件或目录&#xff0c;并可选地压缩为tar压缩包。 创建tar压缩包&#xff1a;tar -cvf archive.tar f…

【深度学习】神经网络术语:Epoch、Batch Size和迭代

batchsize&#xff1a;中文翻译为批大小&#xff08;批尺寸&#xff09;。 简单点说&#xff0c;批量大小将决定我们一次训练的样本数目。 batch_size将影响到模型的优化程度和速度。 为什么需要有 Batch_Size : batchsize 的正确选择是为了在内存效率和内存容量之间寻找最…

Postgresql源码(116)提升子查询案例分析

0 总结 对于SQL&#xff1a;select * from student, (select * from score where sno > 2) s where student.sno s.sno; pullup在pull_up_subqueries函数内递归完成&#xff0c;分几步&#xff1a; 将内层rte score追加到上层rtbable中&#xff1a;rte1是student、rte2带…

nginx编译安装

1.下载nginx&#xff1a; 地址&#xff1a;http://nginx.org/en/download.html 2.安装依赖 安装gcc: yum install -y gcc安装pcre库 yum install -y pcre pcre-devel安装zlib库&#xff1a; yum install -y zlib zlib-devel3.安装nginx ./configure --prefix/usr/local/ngi…

Spark SQL将Hive表中的数据写入到MySQL数据库中

import org.apache.spark.sql.SparkSessionobject HiveToMySQL {def main(args: Array[String]): Unit {// 创建SparkSessionval spark SparkSession.builder().appName("HiveToMySQL").enableHiveSupport().getOrCreate()// 读取Hive表数据val hiveDF spark.tabl…

一体化大气环境监测设备实时守护我们的空气质量

WX-CSQX12 随着空气污染问题的日益严重&#xff0c;大气环境监测设备成为了我们生活中不可或缺的一部分。而一体化的大气环境监测设备&#xff0c;更是为我们的环境保护工作带来了更多的便利和效益。 一体化大气环境监测设备是一种集成了多种功能于一体的环保设备&#xff0c;…

BootStrap【表格二、基础表单、被支持的控件、表单状态】(二)-全面详解(学习总结---从入门到深化)

目录 表格二 表单_基础表单 表单_被支持的控件 表单_表单状态 表格二 紧缩表格 通过添加 .table-condensed 类可以让表格更加紧凑&#xff0c;单元格中的内补&#xff08;padding&#xff09;均会减半 <table class"table table-condensed table-bordered"…

学习量化交易如何入门?

Python 量化入门很简单&#xff0c;只需 3 步就能快速上手! 题主在程序方向没有相关经验&#xff0c;今天就从量化行业的通用语言-Python 着手&#xff0c;教大家如何快速入门。 一、准备工作 在开始 Python 编程之前&#xff0c;首先需要确保你的计算机上安装了合适的 Pytho…

【深度学习】Transformer简介

近年来&#xff0c;Transformer模型在自然语言处理&#xff08;NLP&#xff09;领域中横扫千军&#xff0c;以BERT、GPT为代表的模型屡屡屠榜&#xff0c;目前已经成为了该领域的标准模型。同时&#xff0c;在计算机视觉等领域中&#xff0c;Transformer模型也逐渐得到了重视&a…

【PythonGIS】基于Python面矢量转换线矢量

今天有些不一样&#xff0c;发这篇文章并不是项目需要。单纯的想到有这个功能没使用Python实现&#xff0c;所以就去研究了一下&#xff0c;第一时间就和大家分享。如何使用Python的osgeo库实现面矢量数据与线矢量数据的互相转换。 一、导入所需库 import os from osgeo impor…