Spring中@Autowired和​​@Resource区别

238 阅读2分钟

一、核心区别对比

维度​@Autowired​@Resource
来源Spring原生注解(org.springframework.beans.factory.annotationJava EE标准注解(JSR-250,javax.annotation
默认注入策略按类型(byType)匹配按名称(byName)匹配
是否支持构造器注入✅ 支持❌ 仅支持字段/Setter方法注入
消除歧义方式需配合@Qualifier指定Bean名称直接通过nametype属性指定
是否必需required=true(默认),可设为false允许nullrequired属性,未匹配时抛异常
跨框架兼容性仅Spring生态适用支持所有JSR-250容器(如Jakarta EE)

⚙️ ​二、实现原理详解

1. 处理器与工作流程

  • ​@Autowired
    AutowiredAnnotationBeanPostProcessor处理:

    1. 扫描阶段​:解析类中所有@Autowired注解(字段/构造器/方法);

    2. 注入阶段​:

      • 按类型查找候选Bean → 若唯一则注入;
      • 若多个匹配,按字段名或@Qualifier指定名称筛选;
      • 未匹配且required=true时抛NoSuchBeanDefinitionException
  • ​@Resource
    CommonAnnotationBeanPostProcessor处理:

    1. 名称优先策略​:

      • 若指定name,直接按名称查找Bean;
      • 未指定时,取字段/方法名作为默认名称;
    2. 类型回退策略​:名称未匹配时,按类型查找唯一Bean;

    3. JNDI支持​:可查找非Spring管理的资源(如数据源)。

💡 ​三、典型场景与使用建议

1. 推荐使用@Autowired的场景

  • 构造器注入​:强制依赖不可变对象(如数据库连接);
  • 类型安全优先​:结合@Qualifier明确指定Bean;
  • 深度集成Spring​:需与AOP、事务管理等联动。

2. 推荐使用@Resource的场景

  • 名称明确匹配​:Bean名称与字段名一致时更简洁;
  • 跨环境兼容​:项目可能迁移至非Spring容器(如Jakarta EE);
  • JNDI资源注入​:需注入数据源等外部资源。

3. 解决多实现类冲突

// 方案1:@Autowired + @Qualifier
@Autowired 
@Qualifier("mysqlRepo")
private UserRepository repository;

// 方案2:@Resource指定名称
@Resource(name = "mysqlRepo")
private UserRepository repository;


⚠️ ​四、常见问题与避坑指南

  1. 歧义注入异常

    • @Autowired遇多个同类型Bean需@Qualifier
    • @Resource字段名需与Bean名称一致,否则按类型可能失败。
  2. 空指针风险

    • @Autowired(required=false)允许注入null,需判空;
    • @Resource未匹配时直接抛异常,需确保Bean存在。
  3. 循环依赖问题
    两者均可能触发,建议用构造器注入或@Lazy延迟初始化


💎 ​总结

注解适用场景不适用场景
@AutowiredSpring深度集成、构造器注入、类型驱动开发需解耦Spring或名称明确匹配的场景
@Resource跨框架兼容、JNDI资源、名称与字段一致的简单注入构造器注入或需灵活处理null的场景

设计启示​:

  • 强Spring生态选@Autowired,灵活性更高;
  • 需避免厂商锁定选@Resource,标准化更优。
    源码级理解可参考AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor的实现差异。