为什么推荐使用构造函数注入而非@Autowired注解进行字段注入
在 Spring 框架中,推荐使用构造函数注入而非@Autowired注解进行字段注入,主要有以下几个原因:
1. 依赖不可变和空指针安全
- 构造函数注入:使用构造函数注入时,依赖在对象创建时就必须提供,一旦对象创建完成,其依赖关系就固定下来,不会再改变。这有助于确保对象的状态在整个生命周期中都是一致和可预测的。而且,由于依赖是在构造函数中注入的,在使用对象之前,依赖已经被初始化,不会出现空指针异常。
- 举例:假设有一个
UserService类,它依赖于UserRepository。使用构造函数注入的方式如下:
- 举例:假设有一个
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}// 业务方法public User findUserById(Long id) {return userRepository.findById(id);}
}
在这个例子中,UserService在创建时就必须传入UserRepository实例,之后在调用findUserById方法时,userRepository肯定已经被初始化,不会出现空指针问题。
- 字段注入:使用
@Autowired注解进行字段注入时,依赖是在对象创建之后通过反射机制注入的。这就意味着在对象创建和依赖注入之间存在一个短暂的时间窗口,在这个窗口内,依赖可能为空。如果在依赖注入完成之前就访问依赖,就会导致空指针异常。- 举例:同样是
UserService类,使用字段注入的方式如下:
- 举例:同样是
public class UserService {@Autowiredprivate UserRepository userRepository;// 业务方法public User findUserById(Long id) {return userRepository.findById(id);}
}
在这个例子中,如果UserService在构造函数或者其他方法中过早地访问userRepository,而此时依赖注入还未完成,就可能会抛出空指针异常。
2. 便于单元测试
- 构造函数注入:构造函数注入使得单元测试更加简单和直观。在进行单元测试时,只需要创建一个模拟的依赖对象,并通过构造函数传递给被测试对象即可。这使得测试代码与生产代码之间的依赖关系更加清晰,也更容易控制测试环境。
- 举例:对于上述使用构造函数注入的
UserService,单元测试可以这样写:
- 举例:对于上述使用构造函数注入的
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;public class UserServiceTest {@Testpublic void testFindUserById() {// 创建模拟的UserRepositoryUserRepository mockRepository = mock(UserRepository.class);when(mockRepository.findById(1L)).thenReturn(new User());// 通过构造函数创建UserService实例UserService userService = new UserService(mockRepository);// 调用方法进行测试User user = userService.findUserById(1L);assertNotNull(user);}
}
- 字段注入:使用
@Autowired注解进行字段注入时,在单元测试中需要使用反射或者其他复杂的技术来模拟依赖注入。这使得测试代码变得更加复杂,也增加了测试的难度和维护成本。- 举例:对于使用字段注入的
UserService,单元测试可能需要这样写:
- 举例:对于使用字段注入的
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;@SpringBootTest
@ContextConfiguration
public class UserServiceTest {@Autowiredprivate ApplicationContext applicationContext;@Testpublic void testFindUserById() {// 创建模拟的UserRepositoryUserRepository mockRepository = mock(UserRepository.class);when(mockRepository.findById(1L)).thenReturn(new User());// 通过反射设置UserService的userRepository字段UserService userService = applicationContext.getBean(UserService.class);try {java.lang.reflect.Field field = UserService.class.getDeclaredField("userRepository");field.setAccessible(true);field.set(userService, mockRepository);} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}// 调用方法进行测试User user = userService.findUserById(1L);assertNotNull(user);}
}
可以看到,字段注入的测试代码更加复杂,需要使用反射来设置依赖,增加了测试的难度和维护成本。
3. 更好的代码可读性和可维护性
- 构造函数注入:构造函数注入将对象的依赖关系明确地展示在构造函数的参数列表中。这使得代码的阅读者能够一眼看出该对象依赖于哪些其他对象,以及这些依赖是如何被初始化的。这种清晰的依赖关系有助于提高代码的可读性和可维护性。
- 举例:对于前面的
UserService类,通过构造函数注入,我们可以清楚地看到UserService依赖于UserRepository,并且依赖是在构造函数中进行初始化的。
- 举例:对于前面的
- 字段注入:使用
@Autowired注解进行字段注入时,依赖关系被隐藏在字段声明中,没有在构造函数或者其他明显的位置展示。这使得代码的阅读者需要花费更多的时间和精力来理解对象的依赖关系和初始化过程。- 举例:在使用字段注入的
UserService类中,依赖关系通过@Autowired注解隐藏在字段声明中,不直观。
- 举例:在使用字段注入的
相关文章:
为什么推荐使用构造函数注入而非@Autowired注解进行字段注入
在 Spring 框架中,推荐使用构造函数注入而非Autowired注解进行字段注入,主要有以下几个原因: 1. 依赖不可变和空指针安全 构造函数注入:使用构造函数注入时,依赖在对象创建时就必须提供,一旦对象创建完成&…...
如何卸载和升级 Angular-CLI ?
Angular-CLI 是开发人员使用 Angular 的必备工具。然而,随着频繁的更新和新版本的出现,了解如何有效地卸载和升级 Angular-CLI 对开发人员来说至关重要。本指南提供了一个全面的、循序渐进的方法来帮助您顺利过渡到最新版本。 必备条件 确保您的系统上…...
在线excel编辑(luckysheet)
项目地址:Luckysheet: 🚀Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。 可以下载项目使用npm安装运行,也可以用cdn 加载excel文件(使用luckyexcel): …...
【ES6复习笔记】Symbol 类型及其应用(9)
一、Symbol 简介 Symbol 是 JavaScript 中的一种基本数据类型,它表示唯一的标识符。Symbol 的主要目的是防止属性名冲突,尤其是在多个代码库或模块中共享对象时。Symbol 值可以用作对象的属性名,这样可以确保属性名是唯一的,不会…...
[原创](Modern C++)现代C++的第三方库的导入方式: 例如Visual Studio 2022导入GSL 4.1.0
[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共23年] 职业生涯: 21年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi、XCode、Eclipse…...
【ES6复习笔记】Class类(15)
介绍 ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,…...
【Golang 面试题】每日 3 题(六)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
openEuler安装OpenGauss5.0
OpenGauss5.0 Linux服务器 极简版 服务器安装 单节点安装 极简版安装 安装准备 获取安装包 下载地址:https://opengauss.org/zh/download/archive/版本选择:5.0.0 (LTS)系统架构:uname -m操作系统:cat /etc/os-release完整性校…...
20241230 机器学习ML -(1)线性回归(scikitlearn)
机器学习ML入门。 线性回归 ScikitLearnLRRidgeLassoElasticNetL2:解决共线性问题 (Colinearity Problem) L1:特征选择(AI的解释) W=XtX XtY (Xw=Y >> XtXw= XtY) 当 COND(Xtx) ~ infinit, 导致inv(XtX)无解 举例: 12 23 46 XtX=[14,28] [28,56] eigVal=det…...
MacOS下TestHubo安装配置指南
TestHubo是一款开源免费的测试管理工具, 下面介绍MacOS私有部署的安装与配置。TestHubo 私有部署版本更适合有严格数据安全要求的企业,支持在本地或专属服务器上运行,以实现对数据和系统的完全控制。 1、Mac 服务端安装 Mac安装包下载地址&a…...
mysql性能问题排查
生产环境 Mysql执行性能分析 问题排查思路通过 performance_schema 分析performance_schema 说明查询 performance_schema 所有表信息performance_schema 相关表 主要相关介绍events_statements_history 分析慢查询 和查询当时状态字段说明 问题排查思路 查询慢SQL日志查询SQL…...
centos单机部署seata
文章目录 场景分析下载seata包启动 场景 centos7.9 jdk17 安装部署seata 分析 jdk和seata的版本对应关系如图 JDK版本 推荐 Seata 版本 理由 JDK 8 任何 Seata 版本 JDK 8 是 Seata 长期支持的版本,兼容性最好。 JDK 11 Seata 1.2.0 适合需要长期支持且性能较高的应…...
YOLOv9-0.1部分代码阅读笔记-lion.py
lion.py utils\lion.py 目录 lion.py 1.所需的库和模块 2.class Lion(Optimizer): 1.所需的库和模块 # Lion优化器是一种新型的神经网络优化算法,由Google Brain团队通过遗传算法发现,全称为EvoLved SIgn MOmeNtum,意为“进化的符号动…...
运行Zr.Admin项目(前端)
1.确认环境信息 我这里装的是node16.17版本的 官网16版本的最新为v16.20.2,下载链接https://nodejs.org/dist/v16.20.2/node-v16.20.2-x64.msi 2.去掉ssl 进入到Zr.Admin项目根目录,进入到ZR.vue 打开package.json 文件,删除启动命令配置中…...
HarmonyOS NEXT 实战之元服务:静态多案例效果(一)
背景: 前几篇学习了元服务,后面几期就让我们开发简单的元服务吧,里面丰富的内容大家自己加,本期案例 仅供参考 先上本期效果图 ,里面图片自行替换 效果图1代码案例如下: import { authentication } from…...
go下载依赖提示连接失败
1、现象 Go下载模块提示连接失败 dial tcp 142.251.42.241:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.…...
JS 异步 ( 二、Promise 的用法、手写模拟 Promise )
文章目录 一、Promise 基础Promise 作用Promise 语法Promise 内部状态值 和 链式调用Promise 是否为异步执行Promise 常用函数或属性 二、模拟 Promise,加深理解 一、Promise 基础 Promise 作用 1. 回调地狱 想知道 Promise 的作用, 需要先了解一个概念叫…...
五分钟学会如何在GitHub上自动化部署个人博客(hugo框架 + stack主题)
上一篇文章: 10分钟学会免费搭建个人博客(Hugo框架 stack主题) 前言 首先,想要实现这个功能的小伙伴需要完成几个前置条件: 有一个GitHub账号安装了git,并可以通过git推送commit到GitHub上完成第一篇文章…...
【ETCD】【实操篇(十五)】etcd集群成员管理:如何高效地添加、删除与更新节点
etcd 是一个高可用的分布式键值存储,广泛应用于存储服务发现、配置管理等场景。为了确保集群的稳定性和可扩展性,管理成员节点的添加、删除和更新变得尤为重要。本文将指导您如何在etcd集群中处理成员管理,帮助您高效地维护集群节点。 目录 …...
灵当CRM uploadfile.php 文件上传致RCE漏洞复现
0x01 产品简介 灵当CRM是一款专为中小企业打造的智能客户关系管理工具,由上海灵当信息科技有限公司开发并运营。广泛应用于金融、教育、医疗、IT服务、房地产等多个行业领域,帮助企业实现客户个性化管理需求,提升企业竞争力。无论是新客户开拓、老客户维护,还是销售过程管…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...
