@Autowired与@Resource区别详解
本文深入解析了 Spring 框架中 `@Autowired` 和 Java EE 标准 `@Resource` 注解的区别。`@Autowired` 侧重于类型注入,是 Spring 特有的,当存在多个相同类型的 Bean 时,需配合 `@Qualifier` 或 `@Primary` 解决歧义。而 `@Resource` 优先按名称注入,名称不匹配时才按类型注入,更适用于名称明确的场景,且作为 Java EE 规范的一部分,具有更好的可移植性。文章还探讨了在 Spring Boot 开发中,如何根据实际情况选择合适的注解,以及它们在处理多实例 Bean 时的差异和代码可移植性方面的优劣,为开发者提供了清晰的选型指南。
@Autowired按类型注入,需@Qualifier或@Primary解决多实例歧义;@Resource优先按名称注入,名称不匹配时按类型,更利于名称明确的场景。
@Autowired 侧重于按类型进行依赖注入,是 Spring 框架特有的;而 @Resource 则优先按名称进行注入,是 Java EE 规范的一部分,可以脱离 Spring 独立使用。
解决方案
理解 @Autowired
和 @Resource
的区别,说到底就是理解它们在查找和匹配依赖时的策略差异。
@Autowired:Spring 的类型优先策略
@Autowired
是 Spring 框架提供的注解,它的核心思想是“按类型装配”(by type)。当你在一个字段、构造器或 Setter 方法上使用 @Autowired
时,Spring 容器会尝试在它管理的 Bean 中找到一个类型匹配的 Bean 来进行注入。
例如:
@Component public class MyService { @Autowired private MyRepository myRepository; // Spring会寻找MyRepository类型的Bean // ... }
这里,Spring 会在容器中查找 MyRepository
接口或类的实现。如果容器中只有一个 MyRepository
类型的 Bean,那么它就会被成功注入。但如果容器中有多个 MyRepository
类型的 Bean(比如 MyRepositoryImplA
和 MyRepositoryImplB
都实现了 MyRepository
接口),Spring 就会感到困惑,抛出 NoUniqueBeanDefinitionException
异常,因为它不知道该注入哪一个。
为了解决这种歧义,你可以配合 @Qualifier
注解,明确指定要注入的 Bean 的名称:
@Component public class MyService { @Autowired @Qualifier("myRepositoryImplA") // 明确指定Bean的名称 private MyRepository myRepository; // ... }
或者,你也可以将其中一个实现类标记为 @Primary
,告诉 Spring 在有多个相同类型的 Bean 时,优先选择这个:
@Component @Primary public class MyRepositoryImplA implements MyRepository { /* ... */ } @Component public class MyRepositoryImplB implements MyRepository { /* ... */ } // MyService中无需@Qualifier,Spring会默认注入MyRepositoryImplA @Component public class MyService { @Autowired private MyRepository myRepository; // ... }
@Resource:Java EE 的名称优先策略
@Resource
注解是 JSR-250 规范的一部分,这意味着它不局限于 Spring 框架,也可以在其他 Java EE 容器(如 Tomcat、Glassfish)中使用。它的默认行为是“按名称装配”(by name)。
当你在一个字段或 Setter 方法上使用 @Resource
时,它的查找顺序是这样的:
- 按名称查找: 默认情况下,
@Resource
会尝试将注解所在字段的名称(或者 Setter 方法对应的属性名)作为 Bean 的名称去容器中查找。@Component public class MyService { @Resource private MyRepository myRepositoryImplA; // 会尝试查找名为"myRepositoryImplA"的Bean // ... }
如果找到了,就注入。
- 按类型查找: 如果按名称没有找到匹配的 Bean,
@Resource
就会退而求其次,尝试按类型进行查找。如果找到一个类型匹配的 Bean,就注入。如果找到多个类型匹配的 Bean,它会抛出异常。
你也可以通过 @Resource
的 name
属性明确指定要注入的 Bean 的名称:
@Component public class MyService { @Resource(name = "myRepositoryImplA") // 明确指定Bean的名称 private MyRepository myRepository; // ... }
或者通过 type
属性指定类型,但这通常不如 name
属性常用,因为名称匹配是其核心优势:
@Component public class MyService { @Resource(type = MyRepository.class) // 按类型查找 private MyRepository someRepository; // ... }
总结来说,核心差异是:@Autowired
默认是类型优先,需要 Qualifier
辅助名称;@Resource
默认是名称优先,找不到名称再退化到类型。
Spring Boot开发中,何时优先选择@Autowired,何时选择@Resource?
在 Spring Boot 的日常开发中,选择 @Autowired
还是 @Resource
,这其实更多是一种个人习惯和团队规范的体现,当然,也有些场景会让我倾向于某一个。
我个人在多数情况下会更倾向于使用 @Autowired
。为什么呢?因为 Spring Boot 项目本身就是深度依赖 Spring 框架的,@Autowired
作为 Spring 原生的注解,用起来感觉更“顺滑”,也更符合 Spring 的设计哲学——即通过类型来建立依赖关系。当我在一个纯粹的 Spring 环境中工作时,我希望我的代码能够充分利用 Spring 提供的便利,而 @Autowired
恰好提供了这种简洁和直观的类型匹配能力。特别是当我的接口只有一个实现类时,@Autowired
几乎是零配置,非常方便。如果遇到多实现的情况,@Qualifier
的存在也提供了一个优雅的解决方案。
然而,在某些特定的场景下,我会发现 @Resource
更有用武之地。比如,当我在处理一些遗留系统,或者与一些第三方库集成时,这些库可能在 Spring 容器中注册了一些名称很明确的 Bean,但它们的类型可能比较通用,或者我只是想通过一个特定的名称来引用它们。这时候,@Resource
的名称优先匹配策略就显得非常直接和清晰,它能够减少潜在的类型匹配混淆。
再比如,如果我需要在代码中显式地通过一个字符串名称来引用一个 Bean(这在某些动态配置或工厂模式中可能会出现),那么 @Resource(name="beanName")
的表达力就比 @Autowired
结合 @Qualifier("beanName")
显得更直接一些,因为它把“按名称注入”这个意图放在了注解本身。
另外,从代码的可移植性角度看,@Resource
因为是 Java EE 规范的一部分,理论上它的代码可以更容易地迁移到其他支持 JSR-250 的 Java EE 容器中。尽管在 Spring Boot 项目中,这种可移植性优势往往被淡化了(因为你已经选择了 Spring),但对于那些对规范性有较高要求,或者未来有潜在迁移需求的项目,@Resource
确实提供了一种更标准化的选择。
所以,我的经验是:对于大多数 Spring Boot 应用的内部组件依赖,@Autowired
是一个非常好的默认选择;而当涉及到与外部系统集成、处理遗留代码、或者需要通过明确名称来消除歧义时,@Resource
会是更稳健和清晰的选择。
如果存在多个相同类型的Bean,这两种注解会如何处理?
处理多个相同类型的 Bean,是我们在 Spring 开发中经常会遇到的一个挑战,也是区分 @Autowired
和 @Resource
行为的关键点。
@Autowired 的处理方式:
当 Spring 容器中存在多个类型相同的 Bean,而你又使用了 @Autowired
进行注入时,如果没有额外的指示,Spring 会感到“不知所措”,因为它不知道应该选择哪一个 Bean。在这种情况下,它会抛出一个 NoUniqueBeanDefinitionException
异常。这个异常会明确告诉你,容器中找到了多个符合类型的 Bean,需要你进行进一步的明确。
为了解决这个问题,通常有以下几种方法:
使用
@Qualifier
: 这是最常用也最推荐的方式。通过在@Autowired
的同时加上@Qualifier("beanName")
,你可以明确告诉 Spring 要注入哪个具体名称的 Bean。@Service("smsSender") public class SmsSender implements MessageSender { /* ... */ } @Service("emailSender") public class EmailSender implements MessageSender { /* ... */ } @Component public class NotificationService { @Autowired @Qualifier("emailSender") // 明确指定注入名为 "emailSender" 的Bean private MessageSender messageSender; }
使用
@Primary
: 如果你希望在多个相同类型的 Bean 中,有一个是默认优先被注入的,你可以将该 Bean 标记为@Primary
。这样,当 Spring 遇到类型冲突时,会优先选择带有@Primary
注解的 Bean。@Service @Primary // 优先选择这个发送器 public class DefaultSmsSender implements MessageSender { /* ... */ } @Service public class BackupEmailSender implements MessageSender { /* ... */ } @Component public class NotificationService { @Autowired // 会自动注入 DefaultSmsSender private MessageSender messageSender; }
通过参数名匹配(作为后备): 如果没有
@Qualifier
也没有@Primary
,Spring 还会尝试将要注入的字段名或参数名作为 Bean 的名称进行匹配。但这种方式不如前两种明确,且容易引发混淆,我个人不太推荐在多 Bean 场景下依赖它。
@Resource 的处理方式:
@Resource
在处理多个相同类型的 Bean 时,其行为逻辑有所不同,因为它本身就是名称优先的。
优先按名称查找: 当你使用
@Resource
注解时,它会首先尝试根据字段名(或 Setter 方法名)来查找 Bean。如果找到了一个名称匹配的 Bean,即使有多个相同类型的 Bean,它也会直接注入这个名称匹配的 Bean,不会引发歧义。@Service("smsSender") public class SmsSender implements MessageSender { /* ... */ } @Service("emailSender") public class EmailSender implements MessageSender { /* ... */ } @Component public class NotificationService { @Resource // 尝试查找名为 "smsSender" 的Bean private MessageSender smsSender; @Resource // 尝试查找名为 "emailSender" 的Bean private MessageSender emailSender; }
如果按名称未找到,再按类型查找: 如果
@Resource
没有通过名称找到匹配的 Bean,它才会退而求其次,尝试按类型进行查找。在这种情况下,如果容器中存在多个相同类型的 Bean,并且它们都没有被@Resource
的名称属性明确指定,那么@Resource
同样会抛出异常,因为它无法决定注入哪一个。
所以,从处理多 Bean 的角度看,@Resource
在一开始就通过名称匹配的策略,能够在很多情况下避免歧义。而 @Autowired
则需要你显式地通过 @Qualifier
或 @Primary
来解决这种歧义。
从代码可移植性和规范性角度,这两种注解有何优劣?
谈到代码的可移植性和规范性,@Autowired
和 @Resource
确实展现出了不同的哲学和定位。
@Autowired:Spring 框架的深度整合与便捷性
- 优点:
- 与 Spring 深度整合:
@Autowired
是 Spring 框架的核心组成部分,它与 Spring 的 IoC 容器、AOP、事务管理等功能无缝集成。在纯 Spring 或 Spring Boot 项目中,使用@Autowired
感觉非常自然,也最能体现 Spring 的“约定优于配置”理念。 - 简洁性: 对于大多数只有单一实现类的接口,
@Autowired
几乎是零配置,代码非常简洁。 - 类型安全: 默认的类型匹配策略在编译时就能发现一些潜在的类型不匹配问题(当然,运行时找不到 Bean 还是会报错)。
- 与 Spring 深度整合:
- 缺点:
- 框架耦合度高: 这是最主要的“劣势”。
@Autowired
是 Spring 特有的注解,如果你的代码将来需要从 Spring 容器迁移到其他非 Spring 的 IoC 容器(比如一个纯 Java EE 容器,或者一个自定义的轻量级容器),那么所有使用了@Autowired
的地方都需要进行修改。这会增加迁移成本。当然,在实际的 Spring Boot 项目中,这种迁移的可能性通常很低,因为 Spring Boot 本身就意味着对 Spring 生态的深度依赖。 - 默认行为可能引发歧义: 如前所述,在存在多个相同类型的 Bean 时,
@Autowired
默认会报错,需要额外的@Qualifier
或@Primary
来解决。
- 框架耦合度高: 这是最主要的“劣势”。
@Resource:Java EE 标准的通用性与规范性
- 优点:
- 高可移植性: 这是
@Resource
最显著的优势。作为 JSR-250 规范的一部分,@Resource
是 Java EE 容器的标准注解。这意味着使用了@Resource
的代码理论上可以在任何支持 JSR-250 的 Java EE 容器中工作,而不仅仅局限于 Spring。对于那些需要考虑跨平台或未来可能迁移到不同容器的场景,@Resource
提供了一层抽象,降低了框架锁定的风险。 - 规范性: 遵循 Java EE 规范,使得代码在宏观上更具“标准”感,这对于一些对架构规范有严格要求的企业或项目来说可能是一个加分项。
- 名称优先的清晰性: 其默认的名称匹配策略在很多情况下能够更直观地表达注入意图,尤其是在 Bean 名称具有明确业务含义时。
- 高可移植性: 这是
- 缺点:
- 与 Spring 框架的集成不如
@Autowired
紧密: 尽管 Spring 完全支持@Resource
,但它毕竟不是 Spring 原生的。在某些 Spring 特有的高级特性或扩展点上,@Autowired
可能表现得更自然。 - 在 Spring Boot 环境下,可移植性优势可能被弱化: 就像我前面说的,一旦你选择了 Spring Boot,你通常就已经接受了对 Spring 框架的深度依赖。在这种情况下,
@Resource
的可移植性优势在实践中可能并不那么突出。
- 与 Spring 框架的集成不如
我的看法:
在我的实际开发经验中,如果项目是全新的 Spring Boot 应用,且不预期有任何脱离 Spring 框架的可能,我通常会选择 @Autowired
。它更符合 Spring 的编程模型,也更简洁。然而,如果我正在维护一个老项目,或者一个需要与多种技术栈集成的模块,或者团队对 Java EE 规范有特别的偏好,那么 @Resource
就会成为一个非常有吸引力的选择。它提供了一种更标准化的依赖注入方式,让代码看起来更“规矩”一些,也为未来的不确定性留下了一定的缓冲空间。最终的选择,往往是团队技术栈、项目需求和个人偏好综合权衡的结果。
终于介绍完啦!小伙伴们,这篇关于《@Autowired与@Resource区别详解》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

- 上一篇
- Python合并两个字典的三种方法

- 下一篇
- CSS控制表单字段显示隐藏方法
-
- 文章 · java教程 | 1小时前 |
- SpringBoot打包Docker教程详解
- 121浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- JavaFXGridPane动态布局教程
- 175浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- ElasticsearchJava集成与搜索优化技巧
- 202浏览 收藏
-
- 文章 · java教程 | 2小时前 | java Http请求 重定向 httpclient
- Java重定向处理方法详解
- 112浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java大文件分片上传实现方法详解
- 386浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java并发原子读取方法详解
- 404浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- 对象创建流程:类加载与内存分配详解
- 335浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- 解析树转后缀表达式步骤详解
- 501浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Netbox集成PostgreSQL数据库指南
- 391浏览 收藏
-
- 文章 · java教程 | 4小时前 |
- Java边缘计算与OpenCV图像处理实战
- 478浏览 收藏
-
- 文章 · java教程 | 4小时前 |
- Java日志正则表达式解析技巧
- 169浏览 收藏
-
- 文章 · java教程 | 5小时前 |
- SpringBoot第三方Bean排查技巧分享
- 374浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 千音漫语
- 千音漫语,北京熠声科技倾力打造的智能声音创作助手,提供AI配音、音视频翻译、语音识别、声音克隆等强大功能,助力有声书制作、视频创作、教育培训等领域,官网:https://qianyin123.com
- 1162次使用
-
- MiniWork
- MiniWork是一款智能高效的AI工具平台,专为提升工作与学习效率而设计。整合文本处理、图像生成、营销策划及运营管理等多元AI工具,提供精准智能解决方案,让复杂工作简单高效。
- 1111次使用
-
- NoCode
- NoCode (nocode.cn)是领先的无代码开发平台,通过拖放、AI对话等简单操作,助您快速创建各类应用、网站与管理系统。无需编程知识,轻松实现个人生活、商业经营、企业管理多场景需求,大幅降低开发门槛,高效低成本。
- 1143次使用
-
- 达医智影
- 达医智影,阿里巴巴达摩院医疗AI创新力作。全球率先利用平扫CT实现“一扫多筛”,仅一次CT扫描即可高效识别多种癌症、急症及慢病,为疾病早期发现提供智能、精准的AI影像早筛解决方案。
- 1157次使用
-
- 智慧芽Eureka
- 智慧芽Eureka,专为技术创新打造的AI Agent平台。深度理解专利、研发、生物医药、材料、科创等复杂场景,通过专家级AI Agent精准执行任务,智能化工作流解放70%生产力,让您专注核心创新。
- 1140次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览