@Autowired 与 @Resource区别解析

@Autowired 与 @Resource 注解深度解析

一、核心区别对比

特性 @Autowired @Resource
来源 Spring 框架原生注解 JSR-250 标准注解
默认注入方式 按类型(byType) 按名称(byName)
required属性 支持(默认true) 不支持
名称指定方式 需配合@Qualifier 自带name属性
适用场景 Spring生态项目 需要跨框架通用性

二、源码级机制解析

1. @Autowired 工作原理

Spring通过AutowiredAnnotationBeanPostProcessor实现处理:

java 复制代码
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
// 处理@Autowired字段注入
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
// 反射查找@Autowired注解字段和方法
}

// 实际注入逻辑
protected void inject(Object bean, String beanName, PropertyValues pvs) {
// 通过BeanFactory按类型解析依赖
}
}

2. @Resource 工作原理

由CommonAnnotationBeanPostProcessor处理:

java 复制代码
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor {
// 处理@Resource注入
protected Object getResourceToInject(Object target, String requestingBeanName) {
// 先按name查找,找不到再按type查找
}
}

三、实战案例对比

案例1:基础注入场景

java 复制代码
// 服务接口
public interface PaymentService {
void process();
}

// 实现类1
@Service("creditCardPayment")
public class CreditCardPayment implements PaymentService {
public void process() {
System.out.println("信用卡支付");
}
}

// 实现类2
@Service("alipayPayment")
public class AlipayPayment implements PaymentService {
public void process() {
System.out.println("支付宝支付");
}
}
使用@Autowired
java 复制代码
@Controller
public class OrderController {

// 方式1:可能报错(存在多个实现)
@Autowired// 抛出NoUniqueBeanDefinitionException
private PaymentService paymentService;

// 方式2:配合@Qualifier
@Autowired
@Qualifier("alipayPayment")
private PaymentService qualifiedService;

// 方式3:构造函数注入
@Autowired
public OrderController(@Qualifier("creditCardPayment") PaymentService service) {
this.paymentService = service;
}
}
使用@Resource
java 复制代码
@Controller
public class OrderController {

// 方式1:默认按名称匹配
@Resource(name = "alipayPayment")
private PaymentService paymentService;

// 方式2:不指定name时先按字段名匹配,再按类型
@Resource// 自动匹配名为creditCardPayment的bean
private PaymentService creditCardPayment;
}

案例2:集合类型注入

java 复制代码
// 多个同类型Bean
@Service
public class WechatPayment implements PaymentService {
public void process() {
System.out.println("微信支付");
}
}
@Autowired 处理集合
java 复制代码
@RestController
public class PaymentController {

// 自动注入所有PaymentService实现
@Autowired
private List<PaymentService> allPaymentServices;// 包含3个实现

@GetMapping("/payments")
public void listPayments() {
allPaymentServices.forEach(PaymentService::process);
}
}
@Resource 无法直接支持集合注入

四、混合使用场景

案例3:第三方库组件集成

java 复制代码
// 来自其他jar包的组件
public class ExternalService {
private DataSource dataSource;

@Resource// 标准注解,不依赖Spring
public void setDataSource(DataSource ds) {
this.dataSource = ds;
}
}

// Spring配置类
@Configuration
public class AppConfig {

@Bean
public ExternalService externalService() {
return new ExternalService();
}

@Bean
@Qualifier("mainDS")
public DataSource mainDataSource() {
return new HikariDataSource();
}
}

五、异常情况处理

@Autowired 典型异常

java 复制代码
@Component
public class InvalidExample {

// 抛出NoSuchBeanDefinitionException
@Autowired(required = true)// 默认值
private NonExistentService service;

// 抛出NoUniqueBeanDefinitionException
@Autowired
private PaymentService paymentService;// 有多个实现
}

@Resource 典型异常

java 复制代码
@Component
public class ResourceExample {

// 抛出NoSuchBeanDefinitionException
@Resource(name = "unknownBean")
private Object unknown;

// 按名称找不到时尝试按类型,若类型不唯一会报错
@Resource
private PaymentService service;// 可能抛出NoUniqueBeanDefinitionException
}

六、性能对比

操作 @Autowired @Resource
单类型注入 快(直接类型匹配) 中等(先name后type)
多实现类注入 需要额外处理 名称匹配更高效
启动时处理开销 较高 较低

七、最佳实践建议

  1. 推荐使用场景
  • 纯Spring项目:优先使用@Autowired + @Qualifier
  • 需要跨容器通用性:使用@Resource
  • 构造器注入:用@Autowired(Spring推荐方式)
  1. 避免的问题
java 复制代码
// 反例:字段注入+多个实现
@Autowired
private PaymentService paymentService;// 危险!

// 正例:明确指定
@Resource(name = "alipayPayment")
private PaymentService paymentService;
  1. 现代Spring开发建议
java 复制代码
@Service
public class OrderService {

private final PaymentService paymentService;

// 构造器注入(Spring 4.3+可省略@Autowired)
public OrderService(@Qualifier("creditCardPayment") PaymentService paymentService) {
this.paymentService = paymentService;
}
}

八、原理深度剖析

@Autowired 处理流程

  1. 扫描阶段:BeanPostProcessor收集所有@Autowired注解
  2. 解析阶段:按类型从BeanFactory查找匹配bean
  3. 注入阶段:
  • 字段注入:反射直接设值
  • 方法注入:调用setter方法
  1. 异常处理:检查required属性

@Resource 处理流程

  1. 名称解析:先检查name属性或默认字段名
  2. 类型回退:名称找不到时按类型查找
  3. 注入执行:通过Common Annotations API实现

九、扩展应用场景

自定义限定器

java 复制代码
// 自定义限定注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface AlipayQualifier {}

// 使用方式
@Controller
public class CustomController {

@Autowired
@AlipayQualifier
private PaymentService paymentService;
}

// 实现类标记
@Service
@AlipayQualifier
public class AlipayPayment implements PaymentService {
// 实现代码
}

十、版本兼容性

Spring版本 @Autowired 特性 @Resource 支持
2.5+ 基本功能支持 需要手动启用注解驱动
3.0+ 支持构造器注入 自动检测JSR-250注解
4.3+ 构造器注入可省略@Autowired 完整支持
5.0+ 支持Nullable注解 兼容Jakarta EE 9

通过以上对比分析,开发者可以根据具体场景选择合适的依赖注入方式,构建更健壮的应用系统。

相关推荐
葫芦和十三6 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp6 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑7 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯8 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan10 小时前
多Agent之间的区别
后端
青石路12 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充12 小时前
1.面向对象设计思想
后端
IT_陈寒12 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro13 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗13 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端