【Java】Java 中 @Resource 与 @Autowired 的区别详解


文章目录

    • 一、前言
    • 二、两者的来源与定位
    • 三、共同点
    • [四、`@Autowired` 注入机制详解](#四、@Autowired 注入机制详解)
      • [1. 按类型注入(byType)](#1. 按类型注入(byType))
      • [2. 当有多个同类型 Bean 时](#2. 当有多个同类型 Bean 时)
      • [3. 解决方案](#3. 解决方案)
        • [(1)使用 `@Qualifier` 指定 Bean 名称:](#(1)使用 @Qualifier 指定 Bean 名称:)
        • [(2)使用 `@Primary` 标记优先 Bean:](#(2)使用 @Primary 标记优先 Bean:)
      • [4. 支持构造器注入、Setter 注入、字段注入](#4. 支持构造器注入、Setter 注入、字段注入)
      • [5. 支持 `required` 属性](#5. 支持 required 属性)
    • [五、`@Resource` 注入机制详解](#五、@Resource 注入机制详解)
      • [1. 按名称注入(byName)](#1. 按名称注入(byName))
      • [2. 若找不到匹配名称,则按类型注入(byType)](#2. 若找不到匹配名称,则按类型注入(byType))
      • [3. 可通过属性显式指定 Bean 名称](#3. 可通过属性显式指定 Bean 名称)
      • [4. 不支持 `@Primary` 和 `@Qualifier`](#4. 不支持 @Primary@Qualifier)
    • 六、注入顺序对比(核心差异)
    • [七、在 Spring Boot 中的推荐实践](#七、在 Spring Boot 中的推荐实践)
    • 八、实践建议

一、前言

在 Spring 开发中,依赖注入(Dependency Injection, DI) 是最核心的特性之一。

当我们要把一个 Bean 自动注入到另一个类中时,经常会看到两种注解:

java 复制代码
@Autowired
private UserService userService;
java 复制代码
@Resource
private UserService userService;

它们看起来效果相同,但实际上存在底层机制与使用细节的差异

下面将深入剖析两者的区别与最佳实践。


二、两者的来源与定位

注解 所属包 引入规范 依赖容器
@Autowired org.springframework.beans.factory.annotation Spring 框架 Spring
@Resource jakarta.annotation(或旧版 javax.annotation JSR-250 标准 Java EE(兼容 Spring)

简而言之:

  • @AutowiredSpring 专属注解
  • @ResourceJava 官方标准注解

💡 Spring 同时支持两者,但其注入规则不同。


三、共同点

在功能层面,它们都用于实现 依赖自动注入 (即不再手动 new 对象)。

示例:

java 复制代码
@Service
public class OrderService {

    @Autowired
    private UserService userService;

    public void createOrder() {
        userService.notifyUser();
    }
}

或使用 @Resource

java 复制代码
@Service
public class OrderService {

    @Resource
    private UserService userService;

    public void createOrder() {
        userService.notifyUser();
    }
}

两种方式都能正常工作。

但区别在于:当容器中存在多个同类型 Bean 时,它们的注入逻辑完全不同。


四、@Autowired 注入机制详解

1. 按类型注入(byType)

Spring 会优先根据 类型(Type) 查找匹配的 Bean:

java 复制代码
@Autowired
private UserService userService;

如果容器中存在唯一的 UserService 类型 Bean,就能正常注入。


2. 当有多个同类型 Bean 时

java 复制代码
@Service
public class UserServiceA implements UserService {}

@Service
public class UserServiceB implements UserService {}

@Autowired
private UserService userService; // ❌ 报错:NoUniqueBeanDefinitionException

此时 Spring 不知道该注入哪一个。


3. 解决方案

(1)使用 @Qualifier 指定 Bean 名称:
java 复制代码
@Autowired
@Qualifier("userServiceA")
private UserService userService;

(2)使用 @Primary 标记优先 Bean:
java 复制代码
@Service
@Primary
public class UserServiceA implements UserService {}

4. 支持构造器注入、Setter 注入、字段注入

java 复制代码
@Autowired
public OrderService(UserService userService) {
    this.userService = userService;
}

或:

java 复制代码
@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}

推荐使用 构造器注入 ------ 更利于单元测试与不可变设计。


5. 支持 required 属性

java 复制代码
@Autowired(required = false)
private UserService userService;

如果容器中没有该 Bean,不会抛异常,而是注入 null


五、@Resource 注入机制详解

1. 按名称注入(byName)

@Resource 默认优先根据 字段名(Name) 查找 Bean。

java 复制代码
@Resource
private UserService userService;

Spring 会首先尝试匹配 Bean 名称为 "userService" 的对象。


2. 若找不到匹配名称,则按类型注入(byType)

如果容器中没有 "userService" 这个 Bean 名称,Spring 会退而求其次,按类型注入。

⚠️ 若存在多个相同类型 Bean,会抛出 NoUniqueBeanDefinitionException


3. 可通过属性显式指定 Bean 名称

java 复制代码
@Resource(name = "userServiceA")
private UserService userService;

这相当于 @Autowired + @Qualifier("userServiceA")


4. 不支持 @Primary@Qualifier

@Resource 是 Java 标准注解,不依赖 Spring 的扩展机制,因此不支持这两个注解。


六、注入顺序对比(核心差异)

步骤 @Autowired @Resource
默认策略 按类型注入(byType) 按名称注入(byName)
是否支持 @Qualifier ✅ 支持 ❌ 不支持
是否支持 @Primary ✅ 支持 ❌ 不支持
是否可设置 required ✅ 可选 ❌ 无此属性
是否依赖 Spring 框架 ✅ 是 ❌ 否(标准注解)
优先查找 类型 → 名称 名称 → 类型
使用包 org.springframework.beans.factory.annotation jakarta.annotation
常见错误 多个同类型 Bean 报错 名称不匹配时报错

七、在 Spring Boot 中的推荐实践

场景 推荐注解 理由
纯 Spring 项目 @Autowired Spring 原生,功能更强
兼容 Jakarta / JavaEE 项目 @Resource 标准化,跨框架通用
有多个 Bean 需区分时 @Autowired + @Qualifier 精确控制
惰性加载或选填依赖 @Autowired(required = false) 更灵活

💡 Spring 官方文档推荐优先使用 @Autowired,除非需要兼容性或与非 Spring 框架交互。



八、实践建议

  1. 优先使用 @Autowired(尤其在 Spring Boot 项目中);
  2. 当需要按名称注入时,使用:
java 复制代码
@Autowired
@Qualifier("beanName")
  1. 若项目需要兼容 Jakarta EE 或第三方容器,可使用:
java 复制代码
@Resource(name = "beanName")
  1. 避免在同一个项目中混用两者,以保持一致性;
  2. 推荐使用 构造器注入,提高可测试性与代码可维护性。

参考资料

面试突击78:@Autowired 和 @Resource 有什么区别?-阿里云开发者社区

相关推荐
方也_arkling6 小时前
【Java-Day08】static / final / 枚举
java·开发语言
橙淮6 小时前
Spring Bean作用域与生命周期全解析
java·spring
风吹夏回6 小时前
Python 全局异常处理:从“满屏 try-except”到优雅兜底
开发语言·python
Chengbei116 小时前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
llz_1126 小时前
web-第一次课后作业
java·开发语言·idea
小熊Coding7 小时前
Python爬取当当网二手图书项目实战!
开发语言·爬虫·python·beautifulsoup·requests·二手图书
秋97 小时前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本7 小时前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
xiaoshuaishuai87 小时前
C# 内存管理与资源泄漏
开发语言·c#
DIY源码阁7 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse