字段注入(@Autowired 直接写在字段上):为什么它如此流行但又被官方不推荐?它有什么缺点?

为什么IDEA不推荐使用@Autowired和@Resource进行字段注入? IDEA对@Autowired和@Resource字段注入均不推荐,因其存在破坏不可变性、隐藏循环依赖和降低代码可维护性等共性缺陷。唯一推荐的方案是使用构造器注入,通过final字段确保依赖不可变,显式声明依赖关系,提升代码健壮性和可读性。IDEA的警告旨在引导开发者遵循Spring官方规范,避免潜在运行时风险。构造器注入不仅提前暴露循环依赖问题,还便于代码审查和重构,是替代字段注入的最佳实践。 阅读详情

字段注入之所以流行,是因为它看起来太“方便”了;而被官方不推荐,则是因为这种“方便”是以牺牲代码质量、可测试性和健壮性为代价的。


为什么字段注入如此流行?

原因只有一个:极致的简洁。

让我们直观地对比一下代码量:

1. 字段注入 (Field Injection)

@Service
public class OrderService {
    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private UserRepository userRepository;

    // ... 业务逻辑 ...
}

代码干净利落,添加一个新依赖只需要加一行 @Autowired 的字段。对于初学者或者追求快速开发的人来说,诱惑力巨大。

2. 构造函数注入 (Constructor Injection)

@Service
public class OrderService {
    private final ProductRepository productRepository;
    private final UserRepository userRepository;

    // @Autowired // Spring 4.3+ 后,如果只有一个构造函数,此注解可省略
    public OrderService(ProductRepository productRepository, UserRepository userRepository) {
        this.productRepository = productRepository;
        this.userRepository = userRepository;
    }

    // ... 业务逻辑 ...
}

显然,构造函数注入需要写更多的模板代码(boilerplate code),尤其是在依赖项很多的时候。

总结一下流行的原因:

  • 代码少:这是最直接、最表面的原因。
  • 易于添加/删除依赖:增删一个依赖只需要增删一行字段声明,而不需要修改构造函数。
  • 历史原因:在早期的很多教程和老项目中,字段注入非常普遍,导致这种写法被不断地复制和传播。

为什么官方和资深开发者不推荐字段注入?

因为它带来的问题远比它节省的几行代码要严重得多。以下是它的核心缺点:

1. 可测试性差(The #1 Reason)

这是最致命的缺点。使用字段注入的类,在不启动 Spring 容器的情况下,几乎无法进行单元测试。

  • 问题所在:在单元测试中,我们希望能够手动创建被测试类的实例,并为其注入一个伪造的(Mock)依赖。

  • 对于字段注入:

    // 在测试代码中
    OrderService orderService = new OrderService(); 
    // 问题来了:如何把一个 Mock 的 productRepository 传进去?
    // orderService.productRepository 是 private 的,你无法从外部访问和设置它!
    

    为了解决这个问题,你不得不使用反射工具(如 Spring 的 ReflectionTestUtils 或 Mockito 的 @InjectMocks 注解,其底层也是反射)。这让你的测试变得复杂、脆弱,并且依赖于特定的测试框架。

  • 对于构造函数注入:

    // 在测试代码中,一切都变得非常简单和清晰
    ProductRepository mockProductRepo = new MockProductRepository(); // 一个假的实现
    UserRepository mockUserRepo = new MockUserRepository();
    
    // 直接通过构造函数传入 Mock 对象,这是纯粹的 Java,没有任何魔法
    OrderService orderService = new OrderService(mockProductRepo, mockUserRepo);
    
    // 现在可以对 orderService 进行测试了
    
2. 隐藏了类的依赖关系(Violates Design Principles)

一个设计良好的类,应该通过其公共契约(构造函数或公共方法)清晰地表明它需要什么才能工作。

  • 字段注入的类在“撒谎”。它的构造函数是无参的,看起来你可以通过 new OrderService() 轻松创建它。但如果你真的这么做,并在不通过 DI 容器注入依赖的情况下调用其方法,你会在运行时得到一个 NullPointerException。
  • 构造函数注入则非常诚实。它通过构造函数的参数列表明确告诉你:“没有 ProductRepository 和 UserRepository,你就别想创建我!”。这使得类的依赖关系一目了然。
3. 无法创建不可变对象(Immutability)

构造函数注入允许你将字段声明为 final,这意味着一旦对象被创建,它的依赖就不能再被改变。

private final ProductRepository productRepository; // final 关键字

使用 final 的好处是:

  • 线程安全:确保依赖在多线程环境下不会被意外修改。
  • 状态稳定:保证了对象在整个生命周期内依赖的稳定性和一致性。
  • 强制初始化:编译器会强制你在构造函数中对 final 字段进行初始化,从而避免了 NullPointerException。

字段注入无法使用 final,因为对象是先通过无参构造函数创建的,此时字段必须是可变的,以便后续的注入操作能够修改它。

4. 与 IoC 容器强耦合

字段注入的类严重依赖于 Spring 等 DI 容器来为其注入依赖。它在容器之外几乎是个“残废”,无法独立使用。而构造函数注入的类是一个纯粹的 POJO(Plain Old Java Object),它根本不知道 Spring 的存在,可以在任何环境中使用,具有更好的可移植性和重用性。

5. 循环依赖问题
  • 循环依赖:A 依赖 B,同时 B 依赖 A。
  • 构造函数注入:当 Spring 尝试创建 A 时,发现需要 B;然后去创建 B,又发现需要 A。这是一个死循环,Spring 无法解决,于是在启动时会立即抛出 BeanCurrentlyInCreationException。这是好事,因为它让你在第一时间发现并修复这个糟糕的设计。
  • 字段注入:在某些情况下(取决于 Spring 版本和具体配置),Spring 可以通过一个三级缓存的机制“解决”字段注入的循环依赖。它先创建 A 和 B 的不完整实例(依赖字段为 null),放入缓存,然后再进行注入。这虽然让程序启动了,但它掩盖了潜在的设计缺陷,可能导致代码在未来更难理解和维护。

总结

特性字段注入 (@Autowired on field)构造函数注入 (@Autowired on constructor)
简洁性⭐⭐⭐⭐⭐⭐⭐☆☆☆
可测试性⭐☆☆☆☆ (极差)⭐⭐⭐⭐⭐ (极好)
依赖明确性⭐☆☆☆☆ (隐藏依赖)⭐⭐⭐⭐⭐ (明确暴露)
不可变性 (final)❌ 不支持✅ 支持
容器耦合度高低 (纯 POJO)
循环依赖检测可能掩盖问题启动时立即失败 (Fail-Fast)

建议:

  • 优先使用构造函数注入来注入所有必需的依赖。
  • 避免在业务组件(@Service, @Component, @Controller 等)中使用字段注入。
  • 唯一的例外:在测试类中,使用字段注入(如 @Mock 和 @InjectMocks)是可以接受的,因为测试类的目标就是减少模板代码,且其生命周期和作用域与应用组件完全不同。

字段注入是用长期的代码健康和可维护性,去交换那一点点微不足道的短期便利。 这笔交易,非常不划算。

为什么IDEA提示@Autowired不建议字段注入 为什么IDEA提示@Autowired不建议字段注入 在Spring中依赖注入有三大类:字段注入、构造器注入、Setter方法注入。字段注入是将Bean作为字段注入到类中,也是最方便,用的最多的注入方式。构造器注入适用于强制对象注入Setter注入适合可选对象注入字段注入方式应该尽量避免,因为对象无法脱离容器独立运行(话虽这么说,但我还是字段注入用得多,因为方便啊) 阅读详情

相关推荐

为什么spring不推荐@Autowired注入,提示:Field injection is not recommended

缘起 想必你在项目中使用如下代码时经常会看到idea提示了一个警告:Field injection is not recommended @Autowired UserDao userDao; 这个警告的意思就是使用变量依赖注入的方式是不被推荐的。那么为什么编译器要提示这个警告呢?idea给出的解决策略是这样的 Always use constructor based dependency i...

诺浅的专栏 1万+

SpringBoot字段注入和构造函数注入的区别

在SpringBoot中,我们可以使用@Autowired注解来实现依赖注入,即让Spring容器自动为我们的类提供所需的对象。有三种常见的注入方式:字段注入,Setter方法注入和构造函数注入。字段注入:直接在类的属性上使用@Autowired注解,无需编写额外的代码。Setter方法注入:在类的Setter方法上使用@Autowired注解,需要编写相应的Setter方法。构造函数注入:在类的构造函数上使用@Autowired注解,需要编写相应的构造函数。下面是一个简单的例子,假设我们有一个。

我就说我500的博客 3699

Error relaunching VirtualBox VM process:5错误解决

前几天在重新使用VirtualBox的时候出现了一个挺恶心的错误,如图 百度了好久没有找到合适的解决方法。功夫不负有心人,在查阅了vb相关论坛时发现了大牛对此问题的诸多解决方案。下面我把此论坛的内容总结一下,希望对大家有帮助。 论坛链接:Diagnosing VirtualBox Hardening Issues 时间不足的小伙伴可以直接看 解决方法 造成这个错误的主要原因是,windows操作系统与oracle vb的不兼容。有两个方面,一是非官方windows系统中包含了一些没有签名的d

JaCenz的博客 3万+

Spring依赖注入(一):字段注入的方式是如何工作的?

写这篇文章的起因,是因为我想写篇文章来分享一下:Spring是如何解决循环依赖的?然后在分析的时候,我发现如果要想说清楚Spring是如何解决循环依赖的,那么就必须得先说清楚什么是循环依赖?从字面理解,循环依赖肯定是发生在依赖注入的时候,那么Spring依赖注入的方式有三种注入方式,有的注入是能解决的,有的是解决不了的,那么可以解决循环依赖的注入方式的解决方法是什么?不能解决循环依赖的注入方式的原因又是什么?一连串的问题刺激到了我敏感的神经,因此,就这些疑问我打算用四篇文章分别分析它们。

凡夫编程 2056

xHCI驱动学习(1) 核心数据结构

虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。今天来理清USB xHCI相关的数据结构类型usb_hcd、xhci_hcd、hc_driver和全局变量xhci_pci_driver、xhci_hc_driver、xhci_pci_hc_driver之间的关系。

1万+

Win10如何使用BC3.1精简版

Win10如何使用BC3.1精简版 使用Borland C++3.1 学习μC/OS—Ⅱ几乎是现在的普遍做法,但是由于Win10系统不能直接使用BC3.1,所以需要用到DOSBox。 1、解压bc3.1精简版压缩包,本文将BC3.1文件夹复制在D盘下,DOSBOX按照默认路径安装。下图为两者安装目录图示: 2、修改DOSBOX的配置文件,找到DOSBox文件安装路径,记事本方式打开DOSBox 0.74-3 Options.bat文件,在此文件末尾添加: MOUNT C D:\BC//意为把D:\BC目录

qq_45547236的博客 2377

Spring三种注入方式,构造,Setter和字段注入。基于字段注入的缺陷:final修饰,掩盖单一职责,与IOC紧密耦合,隐藏依赖性,无法安检

Spring三种注入方式,构造,Setter和字段注入。基于字段注入的缺陷:final修饰,掩盖单一职责,与IOC紧密耦合,隐藏依赖性,无法安检

qq120631157的博客 496

基于PID算法的循迹小车

这一期为创客们带来基于PID算法的循迹小车制作 1.标准赛道示意图: (该赛道包含了:左直角、右直角、十字路口等路况) 2.灰度传感器安装示意图: (可根据实际情况调节各传感器之间的间距) 3.硬件原理图: 4.控制逻辑: 5.程序如下: #define leftA_PIN 7 #define leftB_PIN 6 #define left_Pwm_PIN 5 #define STBY...

qq_44343584的博客 4万+

【面试题】为什么Spring不建议使用字段注入

2、可能导致空指针异常:一个Bean的初始顺序为静态变量或静态代码块 > 实例变量或初始化语句块 > 构造方法 > 字段注入。字段注入会使得测试类无法直接通过构造器或方法注入模拟对象,从而增加了测试的复杂性。1、Spring框架支持三种主要的注入方式:字段注入、构造器注入、setter方法注入。其中,字段注入是指在类的字段上添加注解来注入依赖。4、无法注入 final 字段: 字段注入无法用于注入 final 字段,这会限制一些设计和测试的可能性。

qq_54245389的博客 1170

基于COMSOL电弧动态仿真模型优化:高收敛性可修改吹弧方案解析

在多物理场耦合分析中,电弧动态仿真历来是数值稳定性的难点:温度从室温跃升至数万开尔文,电导率随温度呈数量级跳变,流动、传热与电磁场相互牵制,极易引发求解器不收敛或初始值不一致等问题。如何构建高收敛性的数值模型,成为开关设备灭弧性能优化的重要技术基础。通过合理的几何简化、全耦合求解器配置、辅助扫描初始化策略以及参数化建模手段,可以实现对吹弧方案的灵活调整与批量寻优,从而系统性评估气流速度、喷口形状、触头间距等关键因素对熄弧性能的影响。这类仿真方法广泛应用于断路器、接触器等高压电器产品研发,为灭弧室结构设计提供

weixin_29758911的博客 350

工业视觉检测实战指南:从硬件配置到AI算法部署

本文提供了一套完整的工业视觉检测系统搭建实战指南。从硬件选型(相机、光源、镜头、工控机)到AI算法(深度学习模型)部署,详细解析了如何为生产线配置一双“会思考的眼睛”。重点探讨了深度学习算法在复杂缺陷识别中的应用,并分享了模型训练、优化及云边协同部署的实战心得,旨在帮助工程师实现从实验室Demo到7x24小时稳定运行的工业落地。

weixin_29051193的博客 457

SpringBoot:不建议使用字段注入

这样,你的依赖就可以作为构造函数的参数来提供,这会使得你的类更易于测试,且更加安全。自 Spring 4.3 开始,如果目标 bean 只定义了一个构造函数,那么这个构造函数就会被自动使用进行依赖注入,因此。Spring Boot 开发。取而代之的是,建议使用。

ThinkStu的博客 9395

基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例

以下是一个基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例。这个系统使用langchain库进行文档处理、检索,以及与大语言模型交互。

max500600的博客 742

为什么Spring不推荐@Autowired用于字段注入?

虽然@Autowired字段注入简单易用,但它在代码可读性、可维护性和测试性方面存在一些严重的缺陷。Spring官方推荐使用构造器注入,因为它能够提高代码的清晰度,减少NPE的发生,并且更利于单元测试。而且在实际开发中,我们也应该尽量遵循这些最佳实践,通过构造器注入来增强代码的健壮性和可维护性。如果你还在使用字段注入,不妨可以尝试将你的代码重构为构造器注入,通过实践来看看它带来的好处。

派大星的博客 1330

华为OD面试手撕真题 【合并相邻且相等的元素】多语言题解

华为OD面试高频手撕真题【合并相邻且相等的元素】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解。

qq_45776114的博客 548

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

为什么IDEA和Spring都不推荐使用@Autowired注入

为什么不推荐使用@Autowired

ZULJ131的博客 3130

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

为什么IDEA提示不推荐@Autowired❓️如果使用@Resource呢❓️

这篇文章介绍@Autowired 字段注入的优缺点,实际中要根据具体的情况去使用不同的注入方式,不要盲目的追随IDEA的推荐!

分享即是最好的学习 4388

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

@Autowired与构造器注入区别,为什么spring推荐使用构造注入而不是Autowired?

使用Spring开发时,我们通常有两种的方式,基于注解@Autowired的依赖注入和基于构造函数的依赖注入。用IDEA开发过程中,如果使用@Autowired注入,通常会有如下警告:这真的是我们代码写错了吗?其实不然,只是用AutoWired注解去进行注入会产生一些隐形问题。

csdn3043663729的博客 2826

为什么官方不推荐使用@Autowired属性注入

由于这种方法要写构造方法,每注入个新变量就要修改,变量一多,构造方法就变得很长。中的@RequiredArgsConstructor注解帮我们实现构造方法。注解时,Lombok 会自动为该类生成一个包含所有==是 Lombok 提供的注解之一。注解会生成一个包含所有类字段的构造方法,包括。

m0_59651968的博客 1744

spring系列之——使用@Autowired注解,不建议基于字段的依赖注入

介绍 使用@Autowired注解基于字段的依赖注入时,IDEA会出现弱警告,如下: 思考:为什么不推荐使用,这种方式是不是有更好的替代方案。 依赖注入方式 依赖注入有三种方式: 基于字段注入 基于构造器注入 基于set方法注入 1、基于字段注入 @Service public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeMapper emp...

weixin_59744818的博客 1万+

为什么@Autowired字段注入不推荐,有什么缺点吗。为什么spring推荐构造函数注入。

但是直接使用构造函数注入又比较麻烦,我们可以使用 Lombok依赖的@RequiredArgsConstructor。

qq_51263863的博客 1045

为什么不推荐使用@AutoWired

使用idea开发中,idea在我们经常使用的注解上添加了警告警告内容为​ 译为:检验信息:​ 报告在Spring组件中注入或自动连接字段。​ 快速修复建议在bean和断言中为强制字段注入基于构造函数的依赖项Spring常用注入方式为三种:属性注入、构造注入、setter注入。属性注入 构造方法注入 set方法注入,set方法注入一样使用注解 ​ 4. 三种方式对比​ 5. 使用属性注入的问题:​如果一定要使用 属性注入,可以用 替代 注解 相当于 注解,默认按照 注入。可以使用 指定Spr

qq_42315935的博客 4801

想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做

Spring依赖注入static静态成员(属性、方法),这里的坑谁用谁知道

架构师:通透,才能写出好代码! 8563

Java 实用注解篇:@Autowired vs @Resource,为什么不推荐使用 @Autowired?

在 Spring Boot 开发中,依赖注入(Dependency Injection,简称 DI)是核心概念,

x² 1929

【Spring】为什么不建议使用@Autowired

Spring官方不推荐使用@Autowired进行字段注入的主要原因是它违反了封装原则、导致依赖关系不明确、难以进行单元测试、可能导致空指针异常以及存在依赖注入的歧义性。为了编写更加健壮、易于理解和维护的代码,建议采用构造器注入或Setter方法注入作为依赖注入的替代方案。

杰叔叔不是个好叔叔的博客 1668

Spring小白必看:为什么不能用@Autowired直接注入字段

直接在字段上注入依赖,觉得这样写起来特别方便。今天我就用生活化的比喻和简单的例子,带你理解为什么字段注入不被推荐,以及更好的做法是什么。它的在线编辑器让我可以随时尝试不同的注入方式,一键运行就能看到效果,不用配置复杂的本地环境。对于新手来说,这种即时反馈的学习方式真的很友好。虽然字段注入写起来快,但构造器注入才是更专业、更安全的选择。希望这篇指南能帮你避开Spring依赖注入的常见陷阱!作为一个刚接触Spring的新手,你可能经常看到别人用。解决方法:重新设计代码结构,或改用setter注入。

NightshadeRaven21的博客 671
上一篇: Excel 如何制作一个仪表盘(Dashboard),把所有关键指标(KPI)集中展示在一页上?
下一篇: 我们每周都要重复完全一样的操作步骤,Excel 能不能录下来,下次一键执行?
冰糖心书房
博客等级 码龄15年 6014粉丝 690原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值