Spring Boot 中各种 Bean 注入方式的优缺点详解(附实战代码)

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

在 Spring Boot 开发中,依赖注入(Dependency Injection, DI)是最核心的概念之一。它帮助我们解耦组件、提高可测试性和维护性。但很多初学者面对@Autowired、构造器注入、Setter 注入、字段注入等不同方式时常常一头雾水:到底该用哪种?它们有什么区别?今天我们就来彻底讲清楚!


一、需求场景

假设你正在开发一个电商系统,有一个OrderService需要调用UserServicePaymentService来完成下单逻辑。

public class OrderService { private UserService userService; private PaymentService paymentService; // ...业务方法 }

那么,如何将UserServicePaymentService注入到OrderService中呢?

Spring 提供了多种注入方式,下面我们一一分析。


二、四种常见注入方式及优缺点对比

1. 字段注入(Field Injection)【不推荐】

@Service public class OrderService { @Autowired private UserService userService; @Autowired private PaymentService paymentService; public void createOrder() { userService.validateUser(); paymentService.processPayment(); } }
✅ 优点:
  • 代码简洁,写起来快。
  • IDE 自动补全支持好。
❌ 缺点(严重!):
  • 无法创建不可变对象:字段是private且没有 setter,外部无法设置,但 Spring 反射强行赋值,破坏封装性。
  • 难以单元测试:无法通过new OrderService(userService, paymentService)构造,必须依赖 Spring 容器或反射设值。
  • 容易产生 NPE:如果忘记加@Autowired或组件未被扫描,运行时才报错。
  • 违反单一职责原则:类依赖太多时不易察觉。

⚠️ Spring 官方从 2017 年起就不推荐使用字段注入,Spring 团队成员多次公开表示应避免。


2. Setter 注入(Setter Injection)

@Service public class OrderService { private UserService userService; private PaymentService paymentService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } @Autowired public void setPaymentService(PaymentService paymentService) { this.paymentService = paymentService; } public void createOrder() { userService.validateUser(); paymentService.processPayment(); } }
✅ 优点:
  • 支持可选依赖(可以不调用 setter)。
  • 对象创建后可以重新设置依赖(灵活性高)。
❌ 缺点:
  • 依赖不是强制的,可能导致对象处于不完整状态
  • 仍需依赖 Spring 调用 setter,单元测试仍不够方便
  • 多个 setter 方法使类膨胀。

📌 适用场景:可选依赖(如插件、策略模式中的可替换组件)。


3. 构造器注入(Constructor Injection)【强烈推荐!】

@Service public class OrderService { private final UserService userService; private final PaymentService paymentService; public OrderService(UserService userService, PaymentService paymentService) { this.userService = userService; this.paymentService = paymentService; } public void createOrder() { userService.validateUser(); paymentService.processPayment(); } }

注意:Spring Boot 2.6+ 默认启用构造器注入,无需加@Autowired(只要只有一个构造函数)。

✅ 优点:
  • 强制依赖:确保对象创建时所有必要依赖都已注入。
  • 不可变性:配合final字段,保证线程安全和对象完整性。
  • 易于单元测试:直接new OrderService(mockUser, mockPay)即可。
  • 符合 SOLID 原则:清晰暴露依赖关系,便于重构。
❌ 缺点:
  • 如果依赖太多(>5 个),构造函数会很长(但这其实是设计问题,说明类职责过重!)。

官方推荐方式!Spring 文档明确指出:优先使用构造器注入


4. 接口注入(Interface Injection)【极少使用】

需要实现特定接口,由容器调用注入方法。Spring原生不支持此方式,属于早期 DI 框架(如 Avalon)的做法。

❌ 不适用于 Spring Boot,直接忽略。


三、反例演示:字段注入导致的问题

反例:单元测试失败

// 使用字段注入的 OrderService @Service public class BadOrderService { @Autowired private UserService userService; // 私有字段,无 setter/构造器 public String process() { return userService.getName(); // 如果 userService 为 null,NPE! } } // 单元测试 @Test void testProcess() { UserService mockUser = mock(UserService.class); when(mockUser.getName()).thenReturn("Alice"); BadOrderService service = new BadOrderService(); // 此时 userService 为 null! assertThrows(NullPointerException.class, service::process); }

💥 你必须用ReflectionTestUtils.setField()才能设值,非常麻烦!

正确做法:构造器注入 + 单元测试

@Test void testProcessWithConstructorInjection() { UserService mockUser = mock(UserService.class); when(mockUser.getName()).thenReturn("Alice"); GoodOrderService service = new GoodOrderService(mockUser); // 直接传入 assertEquals("Alice", service.process()); // 测试通过! }

四、注意事项 & 最佳实践

  1. 默认使用构造器注入:除非依赖是可选的。
  2. 避免字段注入:尤其在团队协作项目中,容易埋雷。
  3. 依赖过多?考虑拆分类:一个类依赖超过 4~5 个 Bean,可能违反单一职责。
  4. 循环依赖问题
    • 构造器注入无法解决循环依赖(启动报错)。
    • 字段/Setter 注入可通过三级缓存解决,但应重构代码避免循环依赖
  5. Lombok 简化构造器(可选):
@Service @RequiredArgsConstructor // 自动生成 final 字段的构造器 public class OrderService { private final UserService userService; private final PaymentService paymentService; }

需要引入 Lombok 依赖,并开启注解处理器。


五、总结对比表

注入方式是否推荐可测试性强制依赖不可变性循环依赖支持
字段注入
Setter 注入⚠️(可选依赖)
构造器注入✅✅✅

六、结语

选择正确的 Bean 注入方式,不仅能写出更健壮的代码,还能大幅提升团队协作效率和可维护性。记住:构造器注入是 Spring Boot 的最佳实践,字段注入虽快但隐患大,慎用!

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

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

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

相关文章

Jackson 1.x到2.x的演进与Spring集成

Jackson 从 1.x 到 2.x 的演进,不仅是一次技术升级,更深刻影响了 Spring 生态(尤其是 Spring MVC 和 Spring Boot)的 JSON 处理方式。下面从 Jackson 自身差异、Spring 对 Jackson 的集成变迁、实际开发中的迁移注意事项 三个维度…

【好写作AI】商科生的“战略外脑”:让你的案例分析,从课后作业变咨询报告

好写作AI官方网址:https://www.haoxiezuo.cn/一、打开一份50页的企业案例,你是否感觉像在“荒野求生”?信息过载:财报、新闻、行业报告…信息像乱箭齐发,不知该接哪支。模型选择困难症:用SWOT、PEST还是波特…

Jackson 1.x核心用法与Spring 3.x集成

一、Jackson 1.x 核心使用方式 1. 基本依赖&#xff08;Maven&#xff09; <dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-asl</artifactId><version>1.9.13</version> </dependency> <de…

【好写作AI】法学“准律师”的智能卷宗:让AI帮你搞定引用与检索的脏活累活

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、写法学论文的你&#xff0c;是否感觉自己像个“人形法律数据库”&#xff1f;为了一个脚注&#xff0c;在《民法典》的1260条里 “大海捞针” &#xff0c;最后发现引用的还是旧司法解释。裁判文书网一搜“高空抛物”…

leetcode 869. Reordered Power of 2 重新排序得到 2 的幂-耗时100

Problem: 869. Reordered Power of 2 重新排序得到 2 的幂 解题过程 耗时100%&#xff0c;2的幂个数有限&#xff0c;所以只需要枚举&#xff0c;统计每个2的幂的数字频次&#xff0c;以及n的数字频次&#xff0c;比较是否存在2的幂的频次和n的频次相同即可 首先求出2的幂&…

RNA-seq数据分析实战 | 2026年第2期,开启你的生信学习之旅

完成本门课程&#xff0c;学员无需写代码&#xff0c;即可完全基于 Galaxy 生信云平台进行 RNA-seq 数据分析&#xff0c;包括上游表达量矩阵的获得和下游发表级统计图表制作。随着测序技术的飞速发展&#xff0c;RNA-seq 已经成为生物医学研究的常规手段&#xff0c; 掌握 RNA…

AI实战篇:RAG评估从0到1落地,让你的检索增强生成系统能量化、能优化

我们是不是都踩过同一个坑&#xff1a;花数周搭建的RAG系统&#xff0c;上线后用户反馈“答非所问”“信息造假”&#xff1b;调整了chunk大小、换了向量模型&#xff0c;却说不清效果提升了多少&#xff1b;生产环境幻觉率忽高忽低&#xff0c;却找不到问题根源。这些问题的关…

从单细胞测序到人群大数据:一文读懂如何利用scRNA-seq与UK Biobank挖掘临床靶点

你是否思考过&#xff0c;在那些错综复杂的肠道神经丛里&#xff0c;胶质细胞真的只是维持结构的“配角”吗&#xff1f;过去我们总把它们看作一类整齐划一的辅助细胞&#xff0c;但最新的研究却打破了这种固有印象。2026年1月8日Neuron杂志发表了由Meenakshi Rao团队完成的研究…

【好写作AI】从“开挂”到“自强”:把AI变成你的私人学术健身教练

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、两个平行宇宙&#xff1a;用同款AI&#xff0c;结不同果宇宙A&#xff08;摆烂版&#xff09;&#xff1a;小张把题目丢给AI&#xff0c;得到一篇流畅论文。答辩时&#xff0c;导师问&#xff1a;“请问你这里用的XX…

跟我学C++中统篇—STL中的bind

一、标准库中的函数绑定 对C11标准比较熟悉的都知道&#xff0c;标准库中提供了一个函数模板std::bind&#xff0c;用于将可调用对象&#xff08;函数&#xff0c;仿函数、函数指针、lambda表达式及函数对象等&#xff09;与一组参数绑定&#xff0c;然后形成一个新的可调用对象…

【好写作AI】别吵了!用AI写的论文,到底算谁的?一个灵魂拷问的终极回答

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、当答辩委员扶了扶眼镜&#xff0c;问出那个致命问题… “同学&#xff0c;听说你这篇论文用了AI辅助&#xff0c;那么我想问&#xff1a;哪些部分是你的&#xff0c;哪些部分是机器的&#xff1f;”空气突然安静。这…

雷池WAF安装

干净的Ubuntu Server 24 # 下载并运行官方安装脚本 bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/manager.sh)"安装后&#xff0c;可以通过frp暴露到公网上 参考&#xff1a; https://blog.csdn.net/lpfasd123/article/details/156835633 ht…

【好写作AI】毕业季“分身术”:用AI把一天48小时的魔法变成现实

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、毕业季的你&#xff0c;是否在扮演“时间扭曲者”&#xff1f;早上&#xff1a;修改论文第8稿&#xff0c;发现文献引用格式全乱。下午&#xff1a;奔赴一场重要的实习面试&#xff0c;路上还在背自我介绍。晚上&…

拥抱大模型:深入剖析 ReAct 的核心原理、技术架构及其对 AI 领域的深远影响

在人工智能的演进历程中&#xff0c;大语言模型展现出了令人惊叹的文本生成能力&#xff0c;但其“黑箱”特性也带来了显著挑战——模型经常产生看似合理但实际错误的“幻觉”回答&#xff0c;缺乏透明推理过程&#xff0c;且无法与外部世界交互获取实时信息。ReAct&#xff08…

5 款 AI 写论文哪个好?实测横评!虎贲等考 AI 凭硬核实力 C 位胜出

毕业季来临&#xff0c;“AI 写论文工具怎么选” 的提问刷爆学术社群。市面上的论文 AI 五花八门&#xff0c;但真正能兼顾学术严谨性、数据真实性、全流程适配性的工具却寥寥无几。作为深耕论文写作科普的测评博主&#xff0c;我耗时一周&#xff0c;对虎贲等考 AI、掌桥科研 …

【好写作AI】一次“氪金”,终身受益?这笔毕业季投资到底值不值?

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、毕业预算&#xff0c;你是否这样分配&#xff1f;聚餐、拍照、毕业旅行&#xff1a;预算拉满&#xff0c;毫不犹豫。买正版软件、知识付费&#xff1a;眉头一皱&#xff0c;开始犹豫。“这钱花得值吗&#xff1f;有没…

从单智能体到多智能体:九种模式教你搭建高效AI应用

想要构建一个智能体应用&#xff0c;最重要的是什么&#xff1f;可能很多人首先会想到要选择一个性能强大的大模型。这个回答没错&#xff0c;毕竟当前的LLM Based Agent哪能缺少LLM的支撑。但事实却是&#xff0c;很多基于先进大模型构建的智能体没能体现出应用效果&#xff0…

虎贲等考 AI:重塑学术写作新范式,全流程智能赋能论文创作

在学术研究的赛道上&#xff0c;论文写作往往是一道横亘在无数科研人与学子面前的难关 —— 选题缺乏方向、文献梳理耗时费力、数据图表制作繁琐、查重降重反复碰壁、答辩准备手忙脚乱…… 这些痛点&#xff0c;曾让无数人在学术之路上步履维艰。 而今&#xff0c;虎贲等考 AI…

从Windows 10上为远程Linux上安装claude code环境

在本地Linux上启动Claude Code&#xff0c;让Claude Code执行下面指令&#xff1a; 先安装sshpass&#xff0c;本地Linux root密码XXXXconnect to remote ubuntu 24 ip 192.168.X.X, user root XXXX, setup 使用清华ubuntu镜像在远程Linux上为用户jiang 安装nvm&#xff0c;然…

Java IO 与 NIO:从 BIO 阻塞陷阱到 NIO 万级并发

文章目录&#x1f3af;&#x1f525; Java IO 与 NIO&#xff1a;从 BIO 阻塞陷阱到 NIO 万级并发&#xff08;实测 10 万 QPS 性能对比&#xff09;&#x1f31f;&#x1f30d; 引言&#xff1a;数字时代的“脉搏”与 IO 性能天花板&#x1f4ca;&#x1f4cb; 第一章&#xf…