Spring 中 @Autowired 修饰构造方法时注意事项

news2025/1/12 3:59:53

代码演示

给定一个类 One,然后看下的几种构造方法什么时候被调用

1、假设现在只有一个默认的空构造方法,代码如下:

@Component
public class One {

}

然后追踪源码,如下所示:

在这里插入图片描述在这里插入图片描述

先拿到所有声明的构造方法

在这里插入图片描述

然后挨个判断构造方法上是否标注了注解 @Autowired、@Value 注解

在这里插入图片描述

AutowiredAnnotationBeanPostProcessor 类在空构造方法中就已经默默的把这两个注解放入到了内存中

在这里插入图片描述

如果构造方法中没标注上述两个注解,并且构造方法中也没有参数,那么就将这个 candidate 候选的构造方法对象赋值给 defaultConstructor 默认的构造方法对象

在这里插入图片描述

最后就是一堆的判断条件,如下所示:

在这里插入图片描述

现在这里假设的是默认的空参数构造方法,所以只能走到 else 逻辑,直接 new 一个数组,不过没啥作用,最终返回的是 null,因为 candidateConstructors 集合中并没有保存对象。

继续回到外面调用处,如下所示:

在这里插入图片描述

determineConstructorsFromBeanPostProcessors() 返回 null,表示没有找到构造方法,那么就只能走最后的兜底逻辑,也就是采用无参构造方法进行实例化 One 类了。

最后构造方法的反射实例化 One 类。

在这里插入图片描述

总结:其实因为类里面不显示书写构造方法的话,默认其实也是有一个无参构造方法存在的,不然你怎么创建对象,那没有构造方法你怎么去实例化对象。从而推断出是不是类里面只要有并且只有1个构造方法存在的时候,不管你是不是无参还是有参,其实从人类的认知里面,只有1个,那么肯定就用你嘛,别无选择。所以 Spring
里面也是这样的,合乎常理。

现在我就把只写一个有参数的构造方法,如下所示:

@Component
public class One {
	public One(Two tw) {
		System.out.println("带有 @Autowired 注解的1个有参构造方法 tw==" + tw);
	}
}

测试后之后很显然是成功的,结果可以正常打印,One 也可以正常实例化,那分析下源码怎么走的,如下所示:

先拿到 One 类中所有的构造方法,目前仅有1个,如下所示:

在这里插入图片描述

然后挨个遍历构造方法,查找是否被 @Autowired 、@Value 注解修饰

在这里插入图片描述

最后就是一堆的判断条件,如下所示:

在这里插入图片描述

可以发现 else if() 逻辑成立,刚好就一个构造方法,并且还是一个有参的构造方法,所以最终 return 出去的就是这个有参构造方法。

然后直接进入 autowireConstructor() 方法,里面会把参数进行实例化,主要调用 getBean(),参数实例化好了之后,在通过反射调用构造方法实例化 One。

在这里插入图片描述

参数的实例化源码如下:

在这里插入图片描述在这里插入图片描述

参数实例化完成之后,通过有参构造方法的调用实例化 One。

总结:只有一个构造方法时,Spring 只会认识这1个构造方法,并且也会把参数实例化。就和加了 @Autowired 注解一个效果感觉。

2、假设一个无参构造方法,还有一个1个参数的有参构造方法,如下所示:

@Component
public class One {
	public One() {
		System.out.println("空的不带 @Autowired 注解的构造方法");
	}

	public One(Two tw) {
		System.out.println("带有 @Autowired 注解的1个有参构造方法 tw==" + tw);
	}
}

Spring 会选择哪个构造方法进行实例化呢?继续追踪源码,如下:

在这里插入图片描述

调用 determineConstructorsFromBeanPostProcessors() 方法取选择用哪个构造方法进行实例化 bean

在这里插入图片描述

获取 One 类的所有构造方法,发现有两个,如下所示:

在这里插入图片描述

findAutowiredAnnotation() 挨个判断构造方法是否被 @Autowired、@Value 注解修饰,很显然目前这里还没有修饰,所以 ann 结果为 null

在这里插入图片描述

将无参构造方法赋值给变量 defaultConstructor ,表示这是无参构造方法,但是并没有什么意义说实话感觉

在这里插入图片描述

最终也是要走这一段逻辑判断,最终结果返回 null

在这里插入图片描述

继续回到外面调用处,如下所示:

在这里插入图片描述

determineConstructorsFromBeanPostProcessors() 返回 null,表示没有找到构造方法,那么就只能走最后的兜底逻辑,也就是采用无参构造方法进行实例化 One 类了

最后构造方法的反射实例化 One 类。

总结:当你有多个构造方法并且没有标注 @Autowired 、@Value 注解时,Spring 最终只会认识无参构造方法,此时如果没有无参构造方法,那么必然就不能够实例化,最终报错。

那么此时我就是不想用这个空构造方法,我就是想用这个有参构造方法,该怎么办么呢?这个时候就可以加上 @Autowired 注解,加上这个注解,Spring 就只会认这个有注解修饰的构造方法,其他的不会用了。

3、多个构造方法时,指定具体的构造方法实例化 bean,如下所示:

指定 Spring 用1个参数的构造方法实例化 One bean

@Component
public class One {
    public One() {
		System.out.println("空的不带 @Autowired 注解的构造方法");
	}


	public One(Two tw, Three th) {
		System.out.println("带有 @Autowired 注解的2个有参构造方法 tw==" + tw + ",th=" + th);
	}

	@Autowired
	public One(Two tw) {
		System.out.println("带有 @Autowired 注解的1个有参构造方法 tw==" + tw);
	}
}

分析下源码如下:

在这里插入图片描述

查找有没有可以使用的构造方法

在这里插入图片描述

获取到 One 类中所有的构造方法

在这里插入图片描述

挨个遍历构造方法是否被 @Autowired 注解修饰,目前这里只有1个被注解修饰

在这里插入图片描述

找到一个被 @Autowired 注解修饰的构造方法,然后加入到 candidates 候选集合中,并且把 requiredConstructor 变量赋值成了当前这个被 @Autowired 注解修饰的构造方法,为什么要赋值这个 requiredConstructor 变量呢?

在这里插入图片描述

为什么要赋值这个 requiredConstructor 变量呢?是因为怕你有很多构造方法时,你都给加上了 @Autowired 注解,这样对于 Spring 其实又不知道该怎么选择了,其实也合乎常理,换做是你,你也选择不知道用哪个。

所以直接就给你抛异常,除非你在把所有的注解 @Autowired(required = false) 这样就不会抛异常了,但是这样 Spring 只能自己去选择参数最多的那个构造方法进行实例化操作了,没有任何意义说实话。

在这里插入图片描述

话题扯回来,继续跟踪源码,又回到这一堆的判断逻辑,不过这个时候,if 判断条件成立,candidates 集合不为空,因为找到了被 @Autowired 注解修饰的构造方法,最后将这个构造方法对象返回出去

在这里插入图片描述

最终进入 autowirdConstructor() 方法

在这里插入图片描述

这是对构造方法中参数的赋值操作

在这里插入图片描述

最后在通过构造方法反射出 One 的实例。

注意在构造方法中出现了循环依赖,会抛出异常,如下所示:

@Component
public class One {
    public One(Two two) {
		System.out.println("空的不带 @Autowired 注解的构造方法 two="+two);
	}
}
@Component
public class Two {
	public Two(One one) {
		System.out.println("空的不带 @Autowired 注解的构造方法 one="+one);
	}
}

因为此时并没有实例化完成,还没有使用到三级缓存,Spring 中解决循环依赖是依赖三级缓存,所以在这里就会出现异常,异常如下:

在这里插入图片描述

另外,我们可以通过构造方法给 Controller 注入 Service 值,如下所示:

@Controller
public class HelloController {

	private final HelloService helloService;

	public HelloController(HelloService helloService) {
		this.helloService = helloService;
		System.out.println("======>"+this.helloService);
	}
}

@Service
public class HelloService {
}

目前这种方式注入是市面上也比较常用的,也是比 @Autowired 注入方式更友好的,毕竟再也不用看黄色警告⚠️了

总结:

1、当有且仅有1个构造方法时,Spring 都只会使用这个构造方法创建实例。

2、Spring 优先选择 被 @Autowired 标注的构造方法

3、当有多个构造方法同时存在时,Spring 默认选择空构造方法,若此时没有空构造方法,就会报错。

4、当有多个方法同时存在时,想指定 Spring 具体用哪个构造方法,可以加上 @Autowired 注解来标识,如果此时有多个 @Autowired 同时存在,需要将所有的 required 修改成 false ,Spring 默认使用参数最多的构造方法

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

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

相关文章

总结Python设置Excel单元格样式的一切,比官方文档还详细

总结Python设置Excel单元格样式的一切,比官方文档还详细 Python对Excel表格处理非常方便,本文专门对Excel单元格样式设置进行总结,日常用到的设置基本都可以用openpyxl库完成。 创建一个表格 openpyxl是第三方库,如果你还没有安…

如何撰写好的科研论文:摘要(1)

导读 本系列将切片介绍如何写好科研论文,包含了:摘要,背景介绍,方法,结果,讨论等,本文[1]将从摘要开始。 1. 标准 Criteriapointline一般背景听众中的每个人都关心的事情。具体背景从每个人都关…

免费内网穿透工具测评对比,谁更好用 1

文章目录1. 前言2. 对比内容1.1官网主页对比1.2 用户注册对比1.3 用户功能页面对比1.4 客户端对比3. 结语1. 前言 自从接触到内网穿透服务,知道能把自家的电脑、树莓派、NAS等等一堆硬件改造成服务器后,笔者就陷入其中无法自拔,一会儿把树莓…

jmeter接口测试之大家都来我家领豆子

一、测试目的: 2万用户不停请求云豆领取接口时,查看服务器内存占用情况,从而确认服务器内存占用异常的情况是否得到修复。 二、测试策略: 用2万个账号,以每2秒100次请求的速度向服务器发出请求,观察内存…

c#入门-顶级语句和Main方法

程序入口 在你运行程序以后会弹出一个窗口,显示一行文字:Hello world 现在将代码中的所有东西再复制一遍。然后运行,就会得到两行Hello world 显然,我们的程序是写在这里的。 在这里写了什么,什么就会生效。 Main方…

【自动化测试】Pytest+Appium+Allure 做 UI 自动化的那些事

文本主要介绍下 PytestAllureAppium 记录一些过程和经历。 法主要用了啥: Python3 Appium Allure-pytest Pytest Appium 不常见却好用的方法 Appium 直接执行 adb shell 方法 Appium 启动时增加 --relaxed-security 参数 Appium 即可执行类似adb shell的方法 appium -p 4…

短视频账号搭建之Banner图和视频封面

前面在我赢小禾呈序里学了账号名称、头像和个人简介设置,今天把账号搭建的最后两部分一起公开: banner图是你主页上面的这个主图。 同样它的存在可以有三个作用: 第一个作用比较简单,就是让你的主页更好看。 听起来太简单了&am…

【软件测试】测试人在团队中没地位?怎么办?为什么会出现这样的问题?

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 为什么会出现这样的…

Linux 学习之:如何让代码在后台保持运行

文章目录nohup 命令使用场景使用方法nohup ... &nohup ... > train.log 2>&1 &结束进程参考文章nohup 命令 使用场景 比如我要在服务器里运行如下代码来训练我的深度学习模型: python train.py但是这样运行你一旦合上笔记本电脑或者换个工作环…

java版商城多商家入驻商城 直播带货商城 电子商务

一个好的SpringCloudSpringBoot b2b2c 电子商务平台涉及哪些技术、运营方案?以下是我结合公司的产品做的总结,希望可以帮助到大家! 搜索体验小程序:海哇 1. 涉及平台 平台管理、商家端(PC端、手机端)、买家…

vxe table 虚拟滚动 表格每一行的高度不一致 出现空白

今天在做表格数据时&#xff0c;发现滚动表格会出现空白区域&#xff0c;如图所示 虚拟滚动表格每一行的高度不一致, 导致表格滚动时出现空白区域 然后在查阅资料时发现有设置:row-config"{height: 70}"这种 &#xff0c;试过发现不行 以下这个不可行 <vxe-grid…

论文常用 | FineBI v6.0 新图表 | 箱形图

箱形图&#xff08;Box-plot&#xff09;又称为盒须图、盒式图或箱线图&#xff0c;是一种用作显示一组数据分散情况资料的统计图&#xff0c;因形状如箱子而得名。在各种领域也经常被使用&#xff0c;常见于品质管理。它主要用于反映原始数据分布的特征&#xff0c;还可以进行…

突破重围,攻“新”为上!凯里亚德与郁锦香酒店以创新势能获投资者青睐

近日&#xff0c;汇聚国内众多投资人的锦江酒店(中国区)品牌沙龙会烟台站顺利举行。本次沙龙活动以“齐风鲁韵 锦绘未来”为主题&#xff0c;锦江酒店(中国区)旗下众多优秀品牌共同亮相。凯里亚德酒店与郁锦香酒店在本次活动中向投资人展示了在如今复杂多变的酒店市场中如何以强…

载波层叠调制在多电平变换器及两电平变换器中的应用

1. 载波层叠调制在MMC中的应用 载波层叠调制在MMC中应用广泛。通过上下桥臂的调制波和多个载波进行比较&#xff0c;得到每个桥臂应该投入的模块数。如下图所示&#xff0c;上下桥臂各有4个模块&#xff0c;每个模块的电容电压是uc&#xff0c;直流侧电压是4uc。A相下桥臂的调制…

Qt 模型视图编程之 ItemDataRole

背景 Qt 中的模型视图架构是用来实现大量数据的存储、处理及其显示的&#xff0c;主要原理是将数据的存储与显示分离&#xff1a;模型定义了标准接口对数据进行访问&#xff1b;视图通过标准接口获取数据并定义显示方式&#xff1b;模型使用信号与槽机制通知视图数据变化。 Q…

C语言百日刷题第十四天

前言 今天是刷题第14天&#xff0c;放弃不难&#xff0c;但坚持一定很酷~ 临近期末&#xff0c;集中把模拟卷的编程题都刷一下 C语言百日刷题第十四天前言模拟题&#xff08;一&#xff09;1.设计程序实现比较两数大小2.排序成绩模拟题&#xff08;二&#xff09;1.求最大值…

力扣(LeetCode)138. 复制带随机指针的链表(C++)

模拟 第一趟遍历&#xff0c;在结点的右侧复制映射。第二趟遍历&#xff0c;复制 randomrandomrandom。第三趟遍历&#xff0c;将链表中的映射结点取出作为新链表。 初始链表如图①。 有必要说明&#xff0c;原结点如 111~555 &#xff0c;映射结点就是 1‘11‘~5‘55‘。 复…

学习笔记--截止12.9 CVAT使用方法、STCN代码使用方法、bitahub使用方法

CVAT使用方法&#xff08;12.5-12.7&#xff09; 对学长来说是一个标注数据集的好工具&#xff0c;但对我来说是个新的知识点 使用这个工具&#xff0c;我们要得到一张有蒙层的图片 然后CVAT的使用方法&#xff08;网上居然没有教程&#xff0c;&#xff0c;&#xff0c;官网的…

金山表单结果如何自动通知至钉钉

金山表单内置了丰富的模版&#xff0c;从表单、接龙、问卷、投票&#xff0c;可以满足你各种表单数据数据收集的需求。但是很多用户经常也会有一个痛点&#xff0c;通过金山表单收集的信息&#xff0c;如何才能实时通知企业微信/钉钉/飞书呢&#xff1f; 比如防疫登记、安全复工…

茶馆无线wifi短信认证方案

茶馆提供公共的无线wifi上网服务&#xff0c;需对用户进行实名认证。手机短信实名认证以其用户体验、综合成本等优势&#xff0c;成为茶馆无线上网认证的首选方案。 一、茶馆如何实现无线wifi短信认证 茶馆要实现访客无线上网短信认证功能&#xff0c;需要借助上网行为管理设备…