为什么Spring官方不推荐使用 @Autowired?
前言
很多人刚接触 Spring 的时候,对 @Autowired 绝对是爱得深沉。
一个注解,轻松搞定依赖注入,连代码量都省了。
谁不爱呢?
但慢慢地,尤其是跑到稍微复杂点的项目里,@Autowired 就开始给你整点幺蛾子。
于是,官方在某些文档和社区交流中提到过:不建议无脑用 @Autowired,而是更推荐构造函数注入。
为什么?是 @Autowired 不行吗?并不是。
它可以用,但问题是:它不是无敌的,滥用起来容易埋坑。
下面就来聊聊为啥官方建议你慎用 @Autowired,顺便再带点代码例子,希望对你会有所帮助。
1. 容易导致隐式依赖
很多小伙伴在工作中喜欢直接写:
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
}
看着挺简单,但问题来了:类的依赖关系藏得太深了。
- 你看这段代码,
MyService和MyRepository的关系其实是个“隐形依赖”,全靠@Autowired来注入。 - 如果有个同事刚接手代码,打开一看,完全不知道
myRepository是啥玩意儿、怎么来的,只有通过 IDE 或运行时才能猜出来。
隐式依赖的结果就是,代码看起来简单,但维护起来费劲。
后期加个新依赖,或者改依赖顺序,分分钟把人搞糊涂。
怎么破?
用 构造函数注入 替代。
@Service
public class MyService {
private final MyRepository myRepository;
// 构造函数注入,依赖一目了然
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
这样做的好处是:
- 依赖清晰:谁依赖谁,直接写在构造函数里,明明白白。
- 更易测试:构造函数注入可以手动传入 mock 对象,方便写单元测试。
2. 会导致强耦合
再举个例子,很多人喜欢直接用 @Autowired 注入具体实现类,比如:
@Service
public class MyService {
@Autowired
private SpecificRepository specificRepository;
}
表面上没毛病,但这是硬邦邦地把 MyService 和 SpecificRepository 绑死了。
万一有一天,业务改了,需要切换成另一个实现类,比如 AnotherSpecificRepository,你得改代码、改注解,连带着测试也崩。
怎么破?
用接口和构造函数注入,把依赖解耦。
@Service
public class MyService {
private final Repository repository;
public MyService(Repository repository) {
this.repository = repository;
}
}
然后通过 Spring 的配置文件或者 @Configuration 类配置具体实现:
@Configuration
public class RepositoryConfig {
@Bean
public Repository repository() {
return new SpecificRepository();
}
}
这么搞的好处是:
- 灵活切换:改实现类时,不用动核心逻辑代码。
- 符合面向接口编程的思想:降低耦合,提升可扩展性。
3. 容易导致 NullPointerException
有些小伙伴喜欢这么写:
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
public void doSomething() {
myRepository.save(); // 啪!NullPointerException
}
}
问题在哪?如果 Spring 容器还没来得及注入依赖,你的代码就跑了(比如在构造函数或初始化方法中直接调用依赖),结果自然就是 NullPointerException。
怎么破?
用构造函数注入,彻底干掉 null 的可能性。
@Service
public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository; // 确保依赖在对象初始化时就已注入
}
public void doSomething() {
myRepository.save();
}
}
构造函数注入的另一个优点是:依赖注入是强制的,Spring 容器不给你注入就报错,让问题早暴露。
4.自动装配容易搞出迷惑行为
Spring 的自动装配机制有时候是“黑魔法”,尤其是当你的项目里有多个候选 Bean 时。比如:
@Service
public class MyService {
@Autowired
private Repository repository; // 容器里有两个 Repository 实现类,咋办?
}
如果有两个实现类,比如 SpecificRepository 和 AnotherRepository,Spring 容器直接报错。解决方法有两种:
- 指定
@Primary。 - 用
@Qualifier手动指定。
但这些方式都让代码看起来更复杂了,还可能踩坑。
怎么破?
构造函数注入 + 显式配置。
@Configuration
public class RepositoryConfig {
@Bean
public Repository repository() {
return new SpecificRepository();
}
}
你明确告诉 Spring 该用哪个实现类,别让容器帮你猜,省得以后“配错药”。
5. 写单元测试非常痛苦
最后,聊聊测试的事儿。
@Autowired 依赖 Spring 容器才能工作,但写单元测试时,大家都不想起 Spring 容器(麻烦、慢)。结果就是:
- 字段注入:没法手动传入 mock 对象。
- 自动装配:有时候不清楚用的 Bean 是哪个,测试难搞。
怎么破?
构造函数注入天生就是为单元测试设计的。
public class MyServiceTest {
@Test
public void testDoSomething() {
MyRepository mockRepository = mock(MyRepository.class);
MyService myService = new MyService(mockRepository);
// 测试逻辑
}
}
看见没?
直接传入 mock 对象,测试简单、优雅。
总结
简单总结下问题:
- 隐式依赖让代码可读性差。
- 强耦合违背面向接口编程。
- 字段注入容易 NPE。
- 自动装配有坑。
- 单元测试不好写。
那到底咋办?用 构造函数注入,清晰、稳健、测试友好,官方推荐不是没道理的。
但话说回来,@Autowired 也不是不能用,只是你得分场景。
开发中,养成用构造函数注入的习惯,能让你的代码更健壮,少挖坑,多干活!
最后说一句(求关注,别白嫖我)
如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。
为什么Spring官方不推荐使用 @Autowired?的更多相关文章
- Spring官方都推荐使用的@Transactional事务,为啥我不建议使用!
GitHub 17k Star 的Java工程师成神之路,不来了解一下吗! GitHub 17k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 17k Star 的Java工 ...
- 想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做
生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习 ...
- Spring官方文档翻译
随笔:有人曾这样评价spring,说它是Java语言的一个巅峰之作,称呼它为Java之美,今天,小编就领大家一起来领略一下spring之美! Spring官方文档:http://docs.spring ...
- Spring 官方教程:使用 Restdocs 创建 API 文档
https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247483998&idx=1&sn=6ae5fa795d36b1 ...
- Spring官方文档翻译(1~6章)
Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...
- IDEA中使用spring官方模板+@Controller
视图层处理http请求用@Controller时,要配合模板的使用,模板类似javaweb中的jsp,但是模板的引擎用的是 thymeleaf ,但是并不推荐. 现在的开发模式都是前后端分离,做后端只 ...
- spring 官方下载地址(Spring Framework 3.2.x&Spring Framework 4.0.x)
spring官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径: h ...
- spring 官方下载地址
SPRING官方网站改版后,建议都是通过Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦. 下给出Spring Framework jar官方直接下载路径: h ...
- SPRING官方网下载地址
SPRING官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径: h ...
- Spring官方网站的改版后下载
Spring官方网站改版很长一段时间后还没有找到直接下载Jar链接包,下面总结了一些方法,可在网上,亲測可用. 1.直接输入地址,改对应版本号就可以:http://repo.springsource. ...
随机推荐
- 自己服务器搭建docker组和环境
1. docker 当然首先安装一下docker,具体怎么 安装,网上搜一下.我用的ubuntu20系统,就是安装一个普通的软件的操作.安装后,运行一下docker run hello-world,运 ...
- C# HttpClient 基本使用方式(一)
.NetCore主要提供了HttpWebRequest,WebClient,HttpClient这三种访问web的方式,其中HttpWebRequest,WebClient都在官方被标注为已过时,如果 ...
- 推荐3款卓越的 .NET 开源搜索组件库
前言 最近有不少同学提问:.NET有哪些开源的搜索组件库可以推荐的吗?,今天大姚给大家推荐3款卓越的 .NET 开源搜索组件库,希望可以帮助到有需要的同学. Elasticsearch .NET El ...
- shell脚本参数读取列表文件,循环执行时,要注意这个列表文件转换成 unix 格式
当报一些很奇怪的错,比如报错多了一个空格,但 vim 看打开没有,比如: 或者肉眼看上去路径正常,但却报路径不存在: 这种时候要使用 dos2unix 工具,把这个列表文件转换一下:
- Vscode 远程切换Python虚拟环境
在VSCode中远程切换Python虚拟环境是一个涉及多个步骤的过程,包括安装必要的扩展.连接到远程服务器.创建或激活虚拟环境,并在VSCode中选择相应的Python解释器.以下是一个详细的步骤指南 ...
- 深入理解 Nuxt.js 中的 app:created 钩子
title: 深入理解 Nuxt 中的 app created 钩子 date: 2024/9/26 updated: 2024/9/26 author: cmdragon excerpt: 摘要:本 ...
- Android性能优化:getResources()与Binder交火导致的界面卡顿优化
背景 某轮测试发现,我们的设备运行一个第三方的App时,卡顿感非常明显: 界面加载很慢,菊花转半天 滑屏极度不跟手,目测观感帧率低于15 对比机(竞品)也会稍微一点卡,但是好很多,基本不会有很大感觉的 ...
- python中队列deque的使用
队列,堆栈是程序开发中常用的两种数据存储模型.python中队列怎么运用呢?以下内容介绍了队列的使用和队列的函数. from collections import deque q = deque() ...
- docker 靶场 笔记
docker 靶场 笔记 搜索 镜像容器 sudo docker search dvwa 查看所有镜像容器 docker ps -a 下载 指定的 镜像 并在后台启动 docker run -itd ...
- 装有docker的虚拟机环境ping宿主机失败
当我用docker network create 创建了一个网络后 [root@localhost ~]# docker network create kong-net 5c035564f9b4649 ...