前言

很多人刚接触 Spring 的时候,对 @Autowired 绝对是爱得深沉。

一个注解,轻松搞定依赖注入,连代码量都省了。

谁不爱呢?

但慢慢地,尤其是跑到稍微复杂点的项目里,@Autowired 就开始给你整点幺蛾子。

于是,官方在某些文档和社区交流中提到过:不建议无脑用 @Autowired,而是更推荐构造函数注入。

为什么?是 @Autowired 不行吗?并不是。

它可以用,但问题是:它不是无敌的,滥用起来容易埋坑。

下面就来聊聊为啥官方建议你慎用 @Autowired,顺便再带点代码例子,希望对你会有所帮助。

1. 容易导致隐式依赖

很多小伙伴在工作中喜欢直接写:

@Service
public class MyService {
@Autowired
private MyRepository myRepository;
}

看着挺简单,但问题来了:类的依赖关系藏得太深了

  • 你看这段代码,MyServiceMyRepository 的关系其实是个“隐形依赖”,全靠 @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;
}

表面上没毛病,但这是硬邦邦地把 MyServiceSpecificRepository 绑死了。

万一有一天,业务改了,需要切换成另一个实现类,比如 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 实现类,咋办?
}

如果有两个实现类,比如 SpecificRepositoryAnotherRepository,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 对象,测试简单、优雅。

总结

简单总结下问题:

  1. 隐式依赖让代码可读性差。
  2. 强耦合违背面向接口编程。
  3. 字段注入容易 NPE。
  4. 自动装配有坑。
  5. 单元测试不好写。

那到底咋办?用 构造函数注入,清晰、稳健、测试友好,官方推荐不是没道理的。

但话说回来,@Autowired 也不是不能用,只是你得分场景。

开发中,养成用构造函数注入的习惯,能让你的代码更健壮,少挖坑,多干活!

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

为什么Spring官方不推荐使用 @Autowired?的更多相关文章

  1. Spring官方都推荐使用的@Transactional事务,为啥我不建议使用!

    GitHub 17k Star 的Java工程师成神之路,不来了解一下吗! GitHub 17k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 17k Star 的Java工 ...

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

    生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习 ...

  3. Spring官方文档翻译

    随笔:有人曾这样评价spring,说它是Java语言的一个巅峰之作,称呼它为Java之美,今天,小编就领大家一起来领略一下spring之美! Spring官方文档:http://docs.spring ...

  4. Spring 官方教程:使用 Restdocs 创建 API 文档

    https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247483998&idx=1&sn=6ae5fa795d36b1 ...

  5. Spring官方文档翻译(1~6章)

    Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...

  6. IDEA中使用spring官方模板+@Controller

    视图层处理http请求用@Controller时,要配合模板的使用,模板类似javaweb中的jsp,但是模板的引擎用的是 thymeleaf ,但是并不推荐. 现在的开发模式都是前后端分离,做后端只 ...

  7. spring 官方下载地址(Spring Framework 3.2.x&Spring Framework 4.0.x)

    spring官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径: h ...

  8. spring 官方下载地址

    SPRING官方网站改版后,建议都是通过Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦. 下给出Spring Framework jar官方直接下载路径: h ...

  9. SPRING官方网下载地址

    SPRING官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径: h ...

  10. Spring官方网站的改版后下载

    Spring官方网站改版很长一段时间后还没有找到直接下载Jar链接包,下面总结了一些方法,可在网上,亲測可用. 1.直接输入地址,改对应版本号就可以:http://repo.springsource. ...

随机推荐

  1. 为什么C++ 单例局部static初始化是线程安全的?

    为什么C++ 单例局部static初始化是线程安全的? const bg::AppSettings& bg::AppSettings::GetInstance() { static AppSe ...

  2. ChatGPT介绍与使用场景

    ChatGPT是OpenAI开发的一款基于GPT-3和GPT-4的人工智能聊天机器人."GPT"代表的是"Generative Pre-trained Transform ...

  3. MoCov1: 无监督视觉表征学习的动量对比《Momentum Contrast for Unsupervised Visual Representation Learning》(MoCo、动量对比、动态字典、队列维护、对比损失InfoNCE)

    现在是2024年6月11日,21:49,刚找好要看的论文,师兄推荐的. 先占个坑,明天看,我累了(我没脑子了). 现在是6月12日,15:49,干正事了(又被别人影响了情绪,这不好,希望你改掉,好的, ...

  4. Angular 18+ 高级教程 – 初识 Angular

    Before Starting 深入学习 Angular 是一件非常耗时耗力的事情. 实施 Angular 到项目中同样也是一件非常耗时耗力的事情. 在我们做出这么大的投入之前,我们有必要先思考以下几 ...

  5. 2019牛客暑期多校训练营(第四场)J-free(分层图最短路)

    >传送门< 题意:给你n个城市,m条道路,经过每一条要花费这条路的代价,现给你k个机会,使得最多k条路的代价为0,问从起点s到终点t花费的最少代价 思路:分层图最短路经典裸题 方法一 Co ...

  6. GPUStack正式发布: 为大模型而生的开源GPU集群管理器

    经过 Seal 研发团队几个月来持续的开发和测试,我们满怀期待及热情地发布新的产品 GPUStack,GPUStack 是一个用于运行 LLM(大型语言模型)的开源 GPU 集群管理器.尽管如今大语言 ...

  7. linux、unix软链接注意事项

    前言 在使用linux过程中,经常使用到软链接(类似windows快捷方式): 创建软链接之后,删除时不注意就会出现到问题 先说结论 删除软链接,确实是使用rm进行删除:但是有个小细节必须要特别注意! ...

  8. Adobe Acrobat XI Pro 合并多个PDF文件时弹出Flash提示

    事件起因: 某知名同事在使用 Acrobat XI Pro 软件合并多个PDF文件时弹出Flash提示报错,需要安装 FlashPlayer   解决办法: 合并文件的时候右上角选项-文件类型,选择& ...

  9. Android Perfetto 系列 3:熟悉 Perfetto View

    1. Perfetto View 界面 抓到 Perfetto Trace 之后,一般是在 ui.perfetto.dev 中打开(如果用官方提供的脚本,则会在抓去结束后自动在这个网站上打开,想看看怎 ...

  10. KubeSphere 社区双周报 | 功能亮点抢“鲜”看 | 2022-09-30

    KubeSphere 从诞生的第一天起便秉持着开源.开放的理念,并且以社区的方式成长,如今 KubeSphere 已经成为全球最受欢迎的开源容器平台之一.这些都离不开社区小伙伴的共同努力,你们为 Ku ...