【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 有什么区别?-阿里云开发者社区

相关推荐
小石头 10086几秒前
【JavaEE】synchronized关键字
java·java-ee
悟空码字2 分钟前
Java实现接口幂等性:程序员的“后悔药”
java·后端
天天摸鱼的java工程师2 分钟前
🔍 MySQL 索引底层原理与 SQL 优化实战:从 B + 树到亿级查询优化
java·后端
IMPYLH5 分钟前
Lua 的 select 函数
java·开发语言·笔记·后端·junit·游戏引擎·lua
小石头 100866 分钟前
【JavaEE】死锁和避免方法
java·java-ee
JienDa10 分钟前
JienDa聊PHP:知乎仿站实战中PHP框架的协同架构方略
开发语言·架构·php
TDengine (老段)11 分钟前
TDengine 时区函数 TIMEZONE 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
hashiqimiya11 分钟前
android将json数据传递到后端springboot
java·开发语言
lijiatu1008611 分钟前
[C++] 上锁、解锁、获取锁、释放锁的区别
开发语言·c++
Yu_00F15 分钟前
SpringBoot自动配置原理学习与基于原理自定义aliyun-oss-spring-boot-starter依赖
java