一、异常错误

在使用 IntelliJ IDEA 进行 Spring 开发时,当使用 @Autowired 注解直接在字段上进行依赖注入时,IDE 会显示黄色警告:

Field injection is not recommended

这个警告出现在以下代码模式中:

@Service
public class UserService {@Autowiredprivate UserRepository userRepository; // 此处会出现警告// 业务方法
}

二、原因

1. 依赖关系不透明(看不出这个类需要什么)

简单理解:就像一个黑盒子,你不知道里面装了什么。

使用 @Autowired 注解直接标注在字段上时,从类的构造函数和方法签名上完全看不出这个类到底需要哪些依赖。

举个例子

// 字段注入 - 看不出依赖关系
public class UserService {@Autowiredprivate UserRepository userRepository;  // 隐藏的依赖@Autowired private EmailService emailService;      // 隐藏的依赖
}// 构造函数注入 - 一目了然
public class UserService {private final UserRepository userRepository;private final EmailService emailService;// 从构造函数就能看出需要哪些依赖public UserService(UserRepository userRepository, EmailService emailService) {this.userRepository = userRepository;this.emailService = emailService;}
}

2. 容易让类变得臃肿(违背单一职责原则)

简单理解:就像一个人身兼数职,什么都管,最后累垮了。

字段注入太方便了,只需要加个 @Autowired 就能引入新依赖,这会让开发者不知不觉地往一个类里塞太多功能。

举个例子

// 不知不觉中类变得很臃肿
public class UserService {@Autowired private UserRepository userRepository;@Autowired private EmailService emailService;@Autowired private SmsService smsService;@Autowired private LogService logService;@Autowired private CacheService cacheService;@Autowired private ValidationService validationService;// ... 还有更多依赖// 这个类现在要管用户、邮件、短信、日志、缓存、验证...// 职责太多了!
}

3. 测试变得复杂(必须启动Spring容器)

简单理解:就像测试一个电器,必须插电才能用,不能单独测试。

使用字段注入的类无法进行纯粹的单元测试,必须启动整个Spring容器才能完成依赖注入,测试变得又慢又复杂。

举个例子

// 字段注入 - 测试困难
public class UserService {@Autowiredprivate UserRepository userRepository;public User findUser(Long id) {return userRepository.findById(id);}
}// 测试时必须这样写
@SpringBootTest  // 必须启动整个Spring容器
class UserServiceTest {@Autowiredprivate UserService userService;@Testvoid testFindUser() {// 测试代码...}
}// 构造函数注入 - 测试简单
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}// 测试时可以这样写
class UserServiceTest {@Testvoid testFindUser() {// 直接创建mock对象,不需要Spring容器UserRepository mockRepo = Mockito.mock(UserRepository.class);UserService userService = new UserService(mockRepo);// 测试代码...}
}

4. 运行时才发现问题(编译期发现不了错误)

简单理解:就像定时炸弹,平时看不出问题,运行时才爆炸。

字段注入使用反射机制,如果配置有问题,只有在程序运行时才会报错,而不是在编译时就能发现。

举个例子

public class UserService {@Autowiredprivate UserRepository userRepository;  // 如果这个Bean不存在public void saveUser(User user) {userRepository.save(user);  // 运行到这里才会报空指针异常}
}

5. 对象状态不完整(可能出现空指针)

简单理解:就像一辆车还没装完轮子就开始开,肯定会出问题。

使用字段注入时,对象先被创建,然后Spring再通过反射设置字段值。在这个过程中,对象处于"半成品"状态,如果此时调用方法可能会出现空指针异常。

举个例子

public class UserService {@Autowiredprivate UserRepository userRepository;// 如果在依赖注入完成前调用这个方法public void doSomething() {userRepository.findAll();  // 空指针异常!因为userRepository还是null}
}

总结:字段注入虽然写起来简单,但会带来很多隐患。就像走捷径一样,看似省事,实际上后患无穷。

三、解决方法

方法一:构造函数注入(推荐)

构造函数注入是 Spring 官方推荐的依赖注入方式:

@Service
public class UserService {private final UserRepository userRepository;// Spring 4.3+ 版本可省略 @Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}// 业务方法
}

优势:

  • 依赖关系在构造函数中明确声明
  • 支持 final 关键字,保证对象不可变性
  • 便于单元测试,可直接传入 Mock 对象
  • 在对象创建时就确保所有依赖已就绪

方法二:Setter 方法注入

适用于可选依赖的场景:

@Service
public class UserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}// 业务方法
}

适用场景:

  • 依赖是可选的
  • 需要在运行时动态改变依赖
  • 存在循环依赖的特殊情况

方法三:关闭 IDE 警告检查

如果项目中必须使用字段注入,可以关闭相关警告:

操作步骤:

  1. 打开 FileSettings(Windows/Linux)或 IntelliJ IDEAPreferences(Mac)
  2. 导航到 EditorInspections
  3. 搜索 “Spring Core: Common problems”
  4. 取消勾选 “Field injection is not recommended”
  5. 点击 Apply 保存设置

最佳实践建议

必需依赖使用构造函数注入:

@Service
public class OrderService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}
}

可选依赖使用 Setter 注入:

@Service
public class NotificationService {private EmailService emailService;private SmsService smsService;@Autowired(required = false)public void setEmailService(EmailService emailService) {this.emailService = emailService;}@Autowired(required = false)public void setSmsService(SmsService smsService) {this.smsService = smsService;}
}

通过采用构造函数注入作为主要方式,可以编写出更加健壮、易测试和易维护的 Spring 应用程序。

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

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

相关文章

智能核心:机器人芯片的科技革新与未来挑战

在人工智能与机器人技术深度融合的今天,机器人芯片作为驱动智能机器的“大脑”,正成为科技竞争的战略制高点。这一微小却至关重要的硬件,决定了机器人的计算能力、响应速度与智能水平,是机器人从“自动化”迈向“自主化”的关键所…

经典扫雷游戏实现:从零构建HTML5扫雷游戏

一、引言 扫雷是一款经典的单人益智游戏,起源于20世纪60年代,并在90年代随着Windows操作系统的普及而风靡全球。本文将详细介绍如何使用现代网页技术(HTML、CSS和JavaScript)从零开始构建一个功能完整的扫雷游戏。我们将涵盖游戏逻…

ccache编译加速配置

ccache 介绍 ccache(“compiler cache”的缩写)是一个编译器缓存,该工具会高速缓存编译生成的信息,并在编译的特定部分使用高速缓存的信息, 比如头文件,这样就节省了通常使用 cpp 解析这些信息所需要的时间。 github :https://github.com/ccache/ccache home:https://c…

数据库主键选择策略分析

为什么不推荐使用数据库自增主键?分库分表问题:自增ID在分库分表场景下会导致ID冲突需要额外机制(如步长设置)来保证全局唯一,增加系统复杂度安全性问题:自增ID容易暴露业务量(如订单号连续)可能被恶意爬取数据分布式系统限制&…

线性代数理论——状态空间的相关概念以及由系统的输入输出导出状态空间描述

线性代数理论——状态空间 状态:动态系统的状态就是指系统的过去、现在、将来的运动状况,精确的说就是状态需要一组必要而充分的数据来表明。 状态变量:可以表达系统运动状态的变量都是状态变量。 状态变量组:可以完全表征系统在时…

【GaussDB】排查应用高可用切换出现数据库整体卡顿及报错自治事务无法创建的问题

【GaussDB】排查应用高可用切换出现数据库整体卡顿及报错自治事务无法创建的问题 背景 某客户在做应用程序的高可用切换测试,在应用程序中,收到了来自数据库的报错,不能创建自治事务 ERROR: autonomous transaction failed to create auton…

shell脚本第五阶段---shell函数与正则表达式

学习目标掌握case语句的基本语法结构掌握函数的定义以及调用掌握常用的正则表达式元字符含义一、case语句case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case var in 定义变量;var代表变量名…

164.在 Vue3 中使用 OpenLayers 加载 Esri 地图(多种形式)

适配:Vue 3 Vite TypeScript(也兼容 JS) 地图引擎:OpenLayers v10 目标:一次性学会 多种 Esri 底图加载方式、注记叠加、动态切换、令牌(Token)鉴权、常见坑位排查。一、效果预览二、为什么选…

深入了解Flink核心:Slot资源管理机制

TaskExecutor、Task 和 Slot 简单来说,它们的关系可以比作:TaskExecutor:一个工厂,拥有固定的生产资源。TaskSlot:工厂里的一个工位。每个工位都预先分配了一份独立的资源(主要是内存)。Task&am…

java web 练习demo。生成简单验证码前端是jsp

目录结构 demo\ ├── WEB-INF\ │ └── weblogic.xml # WebLogic服务器配置文件 ├── demo.iml # IntelliJ IDEA项目配置文件 ├── lib\ # Java EE核心依赖库 │ ├── javax.annotation.jar │ ├── javax.ejb.jar │ ├── javax.…

拥抱智能高效翻译 ——8 款视频翻译工具深度测评

前阵子帮知识博主做跨境视频翻译,踩了不少坑:把 “内卷” 直译成 “involution” 让海外观众困惑,多语种版本赶工 3 天只出 2 种,还得手动核对 “碳中和”“非遗” 这类特色词的译法;用传统工具译完,视频要…

[知识点记录]SQLite 数据库和MySQL 数据库有什么区别?

核心区别:一个“内嵌”,一个“独立”SQLite (你的个人笔记本)本质: 它是“无服务器”的,或者叫“内嵌式”数据库。它不需要一个独立的程序一直在后台运行。你的应用程序(比如Strapi)直接就能读写它的数据库…

【Spark Core】(二)RDD编程入门

目录1 程序入口&#xff1a;SparkContext对象2 RDD的创建2.1 本地创建2.2 读取文件创建3 RDD算子4 常用Transform算子4.1 map算子4.2 flatMap算子4.3 reduceBykey算子4.4 mapValues算子<实例> WordCount4.5 groupBy算子4.6 filter算子4.7 distinct算子4.8 union算子4.9 j…

java IDEA run/Debug异常:“jdk1.8injava.exe“ CreateProcess error=206, 文件名或扩展名太长

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#,Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发…

Java 函数编程之【过滤器filter()合并】【predicate(断言)】与【谓词逻辑】

Java函数式编程之【过滤器filter合并】【predicate&#xff08;断言&#xff09;】与【谓词逻辑】一、合并多个过滤器filter &#xff08;Lambda版本&#xff09;二、合并多个过滤器filter &#xff08;谓词逻辑&#xff08;Predicate&#xff09;版本&#xff09;&#xff08;…

CentOS10安装RabbitMQ

1.下载资源 &#xff08;1&#xff09;下载erlang-rpm 注意&#xff1a;按照图片中的下载&#xff0c;用绿色三角形指向的是重点关注的。 网址&#xff1a; erlang-rpmhttps://github.com/rabbitmq/erlang-rpm/releases &#xff08;2&#xff09;下载rabbitmq-server 注…

JVM——八股文

1. JDK, JRE和JVM的关系JDK JRE Java开发工具JRE JVM Java核心类库JDK供Java程序开发人员开发软件&#xff0c;JRE供客户使用&#xff0c;只需要JVM运行环境即可。JVM运行的是class字节码&#xff0c;不仅能运行Java代码&#xff0c;还能运行其他语言&#xff0c;只要语言能…

骑行把带定期换,维乐 Skin Wrap 把带焕新骑行

在公路骑行的装备体系里&#xff0c;把带是最易被忽视却至关重要的“消耗品”。它是骑手手部与车身的直接连接&#xff0c;每一次转向、变速、刹车&#xff0c;都需通过把带传递力量与操控意图&#xff1b;同时&#xff0c;它还承担着吸汗、减震、保护车把的作用。可长期使用后…

LeetCode100-73矩阵置零

本文基于各个大佬的文章 上点关注下点赞&#xff0c;明天一定更灿烂&#xff01; 前言 Python基础好像会了又好像没会&#xff0c;所有我直接开始刷leetcode一边抄样例代码一边学习吧。本系列文章用来记录学习中的思考&#xff0c;写给自己看的&#xff0c;也欢迎大家在评论区指…

宁波市第八届网络安全大赛 -- Crypto -- WriteUp

宁波市第八届网络安全大赛 – Crypto – WriteUp Three-prime RSA task import gmpy2 from Crypto.Util.number import *from secret import flagp getPrime(512) q getPrime(512) r getPrime(512) n p * q * r random_num getPrime(28) D ((p q r) * random_num) % n …