news 2026/6/19 2:52:55

Spring 依赖注入的三种方式,踩过坑之后我才知道该用哪个

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring 依赖注入的三种方式,踩过坑之后我才知道该用哪个

学 Spring 的时候,依赖注入这个概念本身不算难,但是注入方式有三种,教程里各写各的,看完之后我反而更纠结了:到底该用哪个?

后来在项目中三种都试过一遍,也踩了一些坑,总算搞清楚了它们各自适合什么场景。这里记录一下。

先回顾一下依赖注入是什么

用一句话说就是:你不用自己new对象了,Spring 容器帮你把需要的东西送过来。

举个例子,UserService需要用到UserRepository来查数据库。传统写法是在类里面直接new一个出来,但这样 UserService 就和某个具体的 Repository 实现绑死了。依赖注入的做法是,你只声明"我需要一个 UserRepository",Spring 容器会在运行时把合适的实现塞给你。

那问题就来了:Spring 是怎么把东西塞给你的?这就有了三种方式。

第一种:构造器注入

在构造函数里接收依赖。

@ServicepublicclassUserService{privatefinalUserRepositoryuserRepository;publicUserService(UserRepositoryuserRepository){this.userRepository=userRepository;}}

这是 Spring 官方推荐的方式。我一开始不理解为什么推荐它,觉得写起来还挺啰嗦的,每个依赖都要写一遍构造函数参数。后来踩了几个坑才明白它好在哪里。

第一个好处是,对象在创建出来的那一刻,所有必需的依赖就已经到位了。不会出现用到一半发现某个依赖是 null 的情况。这个听起来理所当然,但其他方式真的不保证这一点。

第二个好处是依赖字段可以声明为finalfinal意味着这个引用一旦赋值就不会再变,在多线程环境下天然安全,不用担心哪个地方偷偷把它改了。

第三个好处是做单元测试的时候特别方便。脱离了 Spring 容器,你直接new UserService(mockRepository)就能测试,不需要启动任何 Spring 的东西。这个在写测试的时候体感很明显。

还有一个小细节:Spring 4.3 之后,如果一个类只有一个构造函数,@Autowired注解可以省略。所以写起来也没那么啰嗦了。

第二种:Setter 注入

容器先把对象创建出来,然后调用 Setter 方法把依赖传进去。

publicclassPaymentService{privatePaymentGatewaygateway;@AutowiredpublicvoidsetGateway(PaymentGatewaygateway){this.gateway=gateway;}}

这种方式的好处是灵活。对象创建之后,你还可以在运行过程中重新调用 Setter 换一个依赖实现进去。

但问题也很明显:对象刚创建出来的时候,依赖可能还没注入。如果在这期间有人调了业务方法,gateway还是 null,直接就空指针了。

我在一个小项目里用过 Setter 注入,当时觉得代码看着还行。后来有次改代码,忘了配置某个 Bean 的注入,跑起来之后隔了很久才报 NullPointerException,排查半天才发现是 Setter 没被调到。如果是构造器注入,启动的时候就会报错,不用等到运行时才炸。

所以 Setter 注入比较适合那种"有没有都行"的依赖。比如某个服务有一个可选的通知功能,不配就用默认的,配了就覆盖。这种场景下 Setter 注入的灵活性就有用了。

第三种:字段注入

直接在字段上加@Autowired,不写构造函数也不写 Setter。

@ServicepublicclassOrderService{@AutowiredprivateOrderRepositoryorderRepository;}

代码最少,一眼看过去特别干净。我刚开始学 Spring 的时候最喜欢这种写法,因为省事。

但用了一段时间之后,问题就出来了。

首先是依赖被藏起来了。你从类的构造函数和公开方法上完全看不出这个类需要什么才能运行。新接手的人看代码,以为OrderService很简单,拿来用才发现背后还藏着一个OrderRepository,得先把这个也配好才行。

其次是没法声明final。因为@Autowired字段注入是 Spring 通过反射在对象创建之后才赋值的,final字段不允许这样操作。

最让我头疼的是写测试的时候。你想给orderRepository传一个 Mock 对象进去,但它是 private 字段,也没有 Setter。要么启动 Spring 测试容器,要么用反射工具强行塞进去。一个简单的单元测试搞得特别复杂。

后来我翻了一些开源项目的代码,发现成熟的代码库几乎不用字段注入。Spring 官方也不推荐在生产代码里大量使用。

所以到底该怎么选

踩完坑之后,我自己的规则是这样的:

大部分情况下用构造器注入。代码虽然多写几行,但依赖关系清清楚楚,启动时就能检查完所有依赖,写测试也最方便。

Setter 注入留给可选依赖。就是那种"没有也能跑,有了更好"的场景。

字段注入能不用就不用。它写起来确实最省事,但省下来的那几行代码,后面排查问题和写测试的时候都得还回去。

最后放一张总结表,方便以后回来翻:

方式代码量依赖安全final测试友好推荐场景
构造器注入稍多保证可以核心业务,绝大多数场景
Setter 注入中等不保证不行一般可选依赖,有默认值
字段注入最少不保证不行尽量别用
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/19 2:48:28

OCAuxiliaryTools:3分钟掌握黑苹果OpenCore配置的终极指南

OCAuxiliaryTools:3分钟掌握黑苹果OpenCore配置的终极指南 【免费下载链接】OCAuxiliaryTools Cross-platform GUI management tools for OpenCore(OCAT) 项目地址: https://gitcode.com/gh_mirrors/oc/OCAuxiliaryTools 还在为复杂的…

作者头像 李华
网站建设 2026/6/19 2:43:01

还在为音频编辑烦恼吗?免费开源神器如何重塑你的创作体验?

还在为音频编辑烦恼吗?免费开源神器如何重塑你的创作体验? 【免费下载链接】audacity Audio Editor 项目地址: https://gitcode.com/GitHub_Trending/au/audacity 你是否曾因专业音频软件的高昂价格望而却步?是否在复杂的音频编辑界面…

作者头像 李华
网站建设 2026/6/19 2:40:43

OpenClaw:面向真实场景的开源机械臂控制底座

1. 项目概述:这不是另一个“玩具级”机器人框架,而是一套面向真实场景的开源机械臂开发底座OpenClaw 这个名字最近在 GitHub Trending 和国内机器人开发者社区里频繁出现,搜索量明显上扬,尤其集中在“openclaw安装”“openclaw 教…

作者头像 李华
网站建设 2026/6/19 2:37:08

Windows 下利用QT编译boost_1_53_0

一、下载源码在boost官网下载源代码找到指定的版本。一、编译源代码将源代码解压后,用CMD命令进入到源代码根目录利用CMD命令如下: bootstrap gcc此命令会在Boost根目录下生成 b2.exe 等必要的编译工具开始编译和安装:bashb2 install --toolsetgcc --bui…

作者头像 李华
网站建设 2026/6/19 2:34:44

3步开启你的光学实验室:零代码探索光的奇妙世界

3步开启你的光学实验室:零代码探索光的奇妙世界 【免费下载链接】ray-optics A web app for creating and simulating 2D geometric optical scenes, with a gallery of (interactive) demos. 项目地址: https://gitcode.com/gh_mirrors/ra/ray-optics 你是否…

作者头像 李华