自动注入相关注解

@Autowired

在使用Spring进行项目开发的时候,会大量使用到自动装配,那自动装配是什么呢?简单来说:Spring 利用依赖注入(DI)功能,完成SpringIOC容器中各个组件之间的依赖关系赋值管理。

@Autowired 是一个Spring框架的原生注解,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作,是 Spring 框架中用于实现依赖注入(Dependency Injection, DI) 的关键注解

  • 自动将容器中已创建的 Bean 注入到当前 Bean 的字段、构造方法或 setter 方法中
  • 避免手动创建对象,实现松耦合的组件协作
  • 遵循 “控制反转(IoC)” 原则,让容器管理对象生命周期

使用@Autowired 时候,容器启动的扫描流程如下:

  • Spring容器在启动时会自动扫描并管理所有带有 @Component@Service@Repository@Controller 等注解的类
  • @Autowired 通过类型匹配(byType)在容器中查找对应的 Bean,自动将匹配的bean注入到指定的位置。

默认情况下,Spring 按类型解析 @Autowired 依赖。如果容器中存在多个相同类型的 Bean,框架将抛出异常。要解决这一冲突,需要明确告诉 Spring 要注入哪个 Bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface PaymentService { ... }

@Service("alipayService")
public class AlipayServiceImpl implements PaymentService { ... }

@Service("wechatPayService")
public class WechatPayServiceImpl implements PaymentService { ... }

@Service
public class OrderService {
@Autowired
private PaymentService paymentService; // 报错:存在两个 PaymentService Bean
}

此时可以通过@Qualifier进行指定名称去装配 bean,它会检查容器,并查找与要自动装配的属性名称完全相同的 Bean 来进行装配,但是也可通过 @Service("自定义名称") 指定)。

1
2
3
4
5
6
@Service
public class OrderService {
@Autowired
@Qualifier("alipayService") // 明确指定注入名为 "alipayService" 的 Bean
private PaymentService paymentService;
}

而且还可以给 Bean 添加 @Primary 注解,标记其中一个作为默认首选。但是在@Qualifier存在情况下会强制指定特定 Bean,优先级高于 @Primary

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
@Primary
public class AlipayServiceImpl implements PaymentService { ... }

@Service
public class WechatPayServiceImpl implements PaymentService { ... }

@Service
public class OrderService {
@Autowired
@Qualifier("wechatPayService") // 即使 AlipayServiceImpl 被 @Primary 标记,仍注入 wechatPayService
private PaymentService paymentService;
}

注意与@Primary@Profile的区别

1
2
3
4
5
6
7
8
9
@Service
@Primary
@Profile("prod") // 生产环境默认使用支付宝
public class AlipayServiceImpl implements PaymentService { ... }

@Service
@Primary
@Profile("dev") // 开发环境默认使用微信支付
public class WechatPayServiceImpl implements PaymentService { ... }

@Autowired 包含两个重要参数:

  1. required(默认 true):

    指定依赖是否必须存在。若为 false,当容器中没有匹配的 Bean 时,注入 null 而不抛出异常

    1
    2
    @Autowired(required = false)
    private UserRepository userRepository; // 允许为 null
  2. @Qualifier 配合使用: 当存在多个同类型 Bean 时,通过 @Qualifier 指定要注入的 Bean 的名称。

@Autowired 可以标注在三个位置,功能等价但使用场景不同:

  1. 字段注入

    在 Bean 实例化后立即注入

    使用 @Autowired 对属性进行注解。这样就不需要使用GetterSetter

    1
    2
    3
    4
    5
    6
    @Service
    public class UserService {
    @Autowired
    private UserRepository userRepository; // 自动注入Repository
    // ...业务逻辑
    }
  2. 构造方法注入

    在 Bean 创建时注入(推荐用于必填依赖)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Service
    public class OrderService {
    private final OrderRepository orderRepository;

    @Autowired
    public OrderService(OrderRepository orderRepository) {
    this.orderRepository = orderRepository;
    }
    // ...
    }

    Spring 4.3 + 后,若构造方法唯一,@Autowired 可省略

  3. Setter 方法注入(支持可选依赖)

    在 Bean 初始化阶段注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Service
    public class LogService {
    private LogRepository logRepository;

    @Autowired(required = false) // 设置为可选依赖
    public void setLogRepository(LogRepository logRepository) {
    this.logRepository = logRepository;
    }
    // ...
    }

在构建 Bean 时,@Autowired 依赖应该可用。否则,如果 Spring 无法解析用于装配的 Bean,它就会阻止 Spring 容器成功启动,并抛出 NoSuchBeanDefinitionException 异常

@Resource

@Resource 是 Java EE(现 Jakarta EE)标准中的依赖注入注解(JSR-250 规范),从 Java 6 开始引入。它的主要作用是将一个资源(Resource)注入到目标对象中,用于描述依赖注入(Dependency Injection, DI)需求,支持 按名称(byName)和按类型(byType)两种注入方式,属于 Java 标准注解,不依赖于 Spring 框架。

它的设计初衷是让 Java 应用能够以统一的方式声明对外部资源(如 Bean、JNDI 资源、数据源、EJB、Web 服务等)的依赖,而不依赖于具体的实现框架(如 Spring、EJB 容器等)。

@Resource用法与@Autowired用法 用法相似,也是做依赖注入的,从容器中自动获取bean。

@Resource 注解有两个核心参数:

  • name:指定要注入的 Bean 名称(byName 方式)

    1
    2
    @Resource(name = "orderRepository")
    private OrderRepository orderRepo;
  • type:指定要注入的 Bean 类型(byType 方式)

    1
    2
    @Resource(type =  CommentService.class)
    private CommentService commentService;

    对于泛型 Bean,需指定具体的泛型参数化类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Service
    public class UserCommentService implements CommentService<UserComment> { ... }

    @Service
    public class ProductCommentService implements CommentService<ProductComment> { ... }

    @Service
    public class CommentConsumer {
    @Resource(type = UserCommentService.class) // 指定具体实现类
    private CommentService<UserComment> userCommentService;
    }

注意:

  • typename 不能同时用于精确匹配,否则会优先按 name 查找
1
2
@Resource(name = "commentService", type = AuditCommentServiceImpl.class) // 可能导致冲突
private CommentService commentService;
  • 若容器中存在多个相同类型的 Bean,会抛出 NoUniqueBeanDefinitionException
  • 此时应改用 @Qualifiername 参数明确指定 Bean 名称。
  • 当不指定任何参数时,默认采用byName方式,且名称为字段名或方法参数名。若字段类型本身已唯一(如具体实现类),无需额外指定 type
  • @Resource 不支持 required=false,不能注入可选依赖。

所以说@Resource是基于名称(byName)注入 Bean,若名称不存在则尝试按类型注入。是J2EE的JSR-250规范的注解。

注入原理与优先级

  • 优先按 name 匹配:如果 name 属性有值,则直接按 name 查找 Bean。

  • name 为空时,按字段名/方法名查找:如果 name 没有指定,则用字段名或 setter 方法名作为 Bean 名称查找。

  • name 匹配不到时,按 type 匹配:如果按 name 没找到,再按 type 匹配(但 type 匹配如果有多个同类型 Bean,会报错)。

  • 都找不到则报错:@Resource 默认是必须注入的,找不到会抛出异常。

@Resource注解的工作流程如下:

  • 在启动spring的时候,首先要启动容器;
  • 启动spring容器时,会默认寻找容器扫描范围内的可加载bean,然后查找哪些bean上的属性和方法上有@Resource注解;
  • 找到@Resource注解后,判断@Resource注解括号中的 name 属性是否为空,如果为空:看spring容器中的bean的 id 与@Resource 要注解的那个变量属性名是否相同,如相同,匹配成功;如果不相同,看 spring 容器中 bean 的 id 对应的类型是否与@Resource要注解的那个变量属性对应的类型是否相等,若相等,匹配成功,若不相等,匹配失败。
  • 如果@Resource注解括号中的name属性不为空,看name的属性值和容器中的bean的id名是否相等,如相等,则匹配成功;如不相等,则匹配失败。

小知识:JSR 是 Java Specification Requests 的缩写,意思是“Java 规范提案”。任何人都可以提交 JSR 给 Java 官方,但只有最终确定的 JSR,才会以 JSR-XXX 的格式发布,如 JSR-250,而被发布的 JSR 就可以看作是 Java 语言的规范或标准。

@Resource 的三种使用场景

  1. 字段注入

    1
    2
    3
    4
    5
    6
    7
    8
    @Service
    public class UserService {
    @Resource // 默认按字段名 "userRepository" 查找Bean
    private UserRepository userRepository;

    @Resource(name = "orderRepository") // 显式指定Bean名称
    private OrderRepository orderRepo;
    }
  2. Setter注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Service
    public class LogService {
    private LogRepository logRepository;

    @Resource // 默认按方法参数名 "logRepository" 查找Bean
    public void setLogRepository(LogRepository logRepository) {
    this.logRepository = logRepository;
    }
    }
  3. 构造方法注入(较少使用)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Service
    public class ProductService {
    private final ProductRepository productRepository;

    @Resource // 按参数名 "productRepository" 查找Bean
    public ProductService(ProductRepository productRepository) {
    this.productRepository = productRepository;
    }
    }

一般情况下,在同时使用 Spring 和 Java EE 标准的项目中,优先使用 @Resource 保持兼容性,避免与 @Autowired 混用,要注意由于 @Resource 不支持required=false,对于可选依赖可使用 @Autowired

1
2
@Resource
private EntityManager entityManager; // JPA标准资源注入

@Inject

@Inject 是 Java EE(现 Jakarta EE)标准中的依赖注入注解(JSR-330 规范),从 Java 6 开始引入。它是 Java 官方提供的依赖注入标准,旨在提供一种与具体框架无关的注入机制,使代码具有更好的可移植性。

所以,当项目需要同时兼容 Spring、CDI(Java EE)等多个依赖注入框架时,项目中有跨框架的情况下,优先使用 @Inject保持可移植性

基于类型的注入@Inject 默认通过类型(byType)查找并注入依赖,与 Spring 的 @Autowired 类似。而且@Inject 默认要求依赖必须存在,相当于 @Autowired (required = true)。若需要可选依赖,需配合其他机制(如 Optional)。

@Inject 本身只支持按类型注入,当存在多个同类型 Bean 时,需配合 @Named 注解(JSR-330 规范)指定名称:

  • 使用 @Named 标记 Bean 名称

    1
    2
    3
    4
    5
    6
    7
    @Service
    @Named("alipayService") // 等同于Spring的@Service("alipayService")
    public class AlipayServiceImpl implements PaymentService { ... }

    @Service
    @Named("wechatPayService")
    public class WechatPayServiceImpl implements PaymentService { ... }

    然后使用 @Named 指定注入的 Bean

    1
    2
    3
    4
    5
    6
    @Service
    public class OrderService {
    @Inject
    @Named("alipayService") // 等同于@Autowired + @Qualifier("alipayService")
    private PaymentService paymentService;
    }

@Inject 的三种使用场景:

  1. 构造方法注入

    在构造方法上使用 @Inject 时,其参数在运行时由配置好的IoC容器提供,规范中规定向构造方法注入的参数数量是0个或多个,所以在不含参数的构造方法上使用 @Inject 注解也是合法的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Service
    public class UserService {
    private final UserRepository userRepository;

    @Inject // Spring 4.3+ 后可省略 @Inject
    public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
    }
    }
  2. 字段注入

    1
    2
    3
    4
    5
    @Service
    public class OrderService {
    @Inject
    private OrderRepository orderRepository;
    }
  3. 方法注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Service
    public class LogService {
    private LogRepository logRepository;

    @Inject
    public void setLogRepository(LogRepository logRepository) {
    this.logRepository = logRepository;
    }
    }

@ConfigurationProperties

那么他们之间的区别是什么

在Spring中依赖注入可以使用@Autowired、@Resource和@Inject来完成,并且在一般的使用中是可以相互替换的(注意是一般),不过三者还是有区别

@Autowired注解:

  • 是Spring本身替换的注解(org.springframework.beans.factory.annotation.Autowired),需要导入Spring相应的jar包才能使用

  • 可以标注的位置:构造器、方法、方法参数、变量域和注解上面

  • 在Spring容器解析@Autowired注解时,使用的后置处理器为AutowiredAnnotationBeanPostProcessor,在这个后置处理的注释中有这么一段:

    1
    2
    3
    4
    5
    6
    7
    8
    {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
    * implementation that autowires annotated fields, setter methods, and arbitrary
    * config methods. Such members to be injected are detected through annotations:
    * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
    * annotations.
    *
    * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
    * if available, as a direct alternative to Spring's own {@code @Autowired}.

    大约意思就是,AutowiredAnnotationBeanPostProcessor 是一个 BeanPostProcessor 实现,其主要职责是:

    • 自动装配(注入)被注解标记的 字段(fields)Setter 方法任意配置方法
    • 这些需要被注入的成员(members)通过注解来识别,默认支持:
      • Spring 原生的 @Autowired@Value 注解。
      • JSR-330 标准的 @Inject 注解(如果项目中存在该依赖)。如果项目中引入了 JSR-330(Jakarta Inject) 的依赖(如 javax.inject:javax.inject:1),该处理器也会支持 @Inject 注解,其功能与 @Autowired 基本相同
    • 在 Bean 实例化后、初始化前,该处理器会扫描 Bean 的字段、方法,识别带有 @Autowired@Inject@Value 的成员。然后从 Spring 容器中查找匹配的 Bean 并完成注入。
  • @Autowired注解有一个required属性,当指定required属性为false时,意味着在容器中找相应类型的bean,如果找不到则忽略,而不报错(这一条是两个注解所没有的功能)。

  • 默认优先按照类型去容器中找对应的组件,找到就赋值,如果找到多个相同类型的组件,再将属性的名称作为组件的 id 去容器中查找,如果组件 id 对象的bean不存在,而且required属性为true,就报错。

  • 支持@Primary注解,让Spring进行自动装配的时候,默认使用首选的bean

@Resource 注解

  • JSR250规范提供的注解(javax.annotation.Resource),不需要导入格外的包,这个注解在JDK的rt.jar包中

  • 可以标注的位置:TYPE(表示可以标注在接口、类、枚举),FIELD(变量域)和METHOD(方法)上面。

  • 在Spring容器解析@Resource注解时,使用的后置处理器为CommonAnnotationBeanPostProcessor,在这个后置处理的注释中有这么一段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
    * that supports common Java annotations out of the box, in particular the JSR-250
    * annotations in the {@code javax.annotation} package. These common Java
    * annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2),
    * as well as in Java 6's JAX-WS.
    *
    * <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}
    * and {@link javax.annotation.PreDestroy} annotations - as init annotation
    * and destroy annotation, respectively - through inheriting from
    * {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
    *
    * <p>The central element is the {@link javax.annotation.Resource} annotation
    * for annotation-driven injection of named beans, by default from the containing
    * Spring BeanFactory, with only {@code mappedName} references resolved in JNDI.
    * The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups
    * equivalent to standard Java EE 5 resource injection for {@code name} references
    * and default names as well. The target beans can be simple POJOs, with no special
    * requirements other than the type having to match.

    大约意思就是CommonAnnotationBeanPostProcessor 是一个 BeanPostProcessor 实现,其主要职责是:

    • 支持 Java 标准注解(无需额外配置),特别是 JSR-250 规范中的 javax.annotation 包注解。
    • 这些注解广泛应用于 Java EE 5 技术(如 JSF 1.2)和 Java 6 的 JAX-WS 中。
    • 具体支持注解
      • @PostConstruct:标记 Bean 初始化后执行的方法(等价于 Spring 的 @PostConstruct)。
      • @PreDestroy:标记 Bean 销毁前执行的方法(等价于 Spring 的 @PreDestroy)。
    • 若同时使用@Resource@Autowired,Spring 会按以下顺序处理:
      1. @Resource(由 CommonAnnotationBeanPostProcessor 处理)
      2. @Autowired(由 AutowiredAnnotationBeanPostProcessor 处理)

    CommonAnnotationBeanPostProcessor 是 Spring 框架中支持 Java 标准注解 的核心组件,它通过 @Resource 实现按名称注入,并提供对 @PostConstruct@PreDestroy 的支持,使 Spring 应用能够无缝集成 Java EE 标准注解,提高代码的可移植性和兼容性。

  • 默认是按照组件名称进行装配的,@Autowired是根据类型,@Resource是根据组件名称

  • 支持@Primary注解,不过首先按照会按照名称进行注入bean,先不执行@Primary注解标注的优先的依赖注入,如果Spring IOC容器中没有该Bean,此时再按照@Primary注解标注的bean进行装配

@Inject 注解

  • JSR330规范提供的注解(javax.inject.Inject),主要导入javax.inject包才能使用
  • 可以标注的位置:方法、构造器和变量域中
  • 在Spring容器解析@Inject注解时,使用的后置处理器和@Autowired是一样的,都是AutowiredAnnotationBeanPostProcessor
  • 由于@Inject注解没有属性,在加载所需bean失败时,会报错
  • 除了上面的不同点之后,@Inject和@Autowired完全等价
特性 @Resource (JSR-250) @Inject (JSR-330) @Autowired (Spring)
所属规范 Java 标准(Jakarta EE, JSR-250) Java 标准(Jakarta EE, JSR-330) Spring 框架原生注解
默认查找方式 按名称(byName),字段名或方法参数名 按类型(byType) 按类型(byType)
支持参数 name, type, mappedName - (配合 @Named 使用) required, value(Spring 4.3+ 支持)
多 Bean 处理 显式指定 name 或 type 配合 @Named 或自定义限定符 配合 @Qualifier@Primary
依赖强制性 必须存在(无 required 参数) 必须存在(无等效 required=false) 支持 required=false(允许 null)
可选依赖支持 不支持,需结合 @Autowired (required=false) 需配合 Optional<>, Provider@Nullable 直接通过 required=false 支持
注入方式支持 字段、Setter 方法、构造方法(较少用) 字段、Setter 方法、构造方法 字段、Setter 方法、构造方法、任意方法
优先级处理 name 参数 > type 参数 > 字段名 @Named 指定名称 > 类型匹配 @Qualifier > @Primary > 类型匹配
容器查找顺序 1. 按 name 查找 2. 按 type 查找 1. 按类型查找 2. 按 @Named 名称查找 1. 按类型查找 2. 按 @Qualifier 名称查找 3. 按 @Primary
与其他注解配合 @PostConstruct, @PreDestroy @Named, @Scope @Qualifier, @Primary, @Lazy
常见场景 Java EE 兼容项目、JNDI 资源注入 跨框架项目、Java 标准依赖注入 Spring 项目的首选注入方式
历史兼容性 Java 6+ Java 6+ Spring 2.5+
框架集成性 支持 JSF、EJB 等 Java EE 技术 支持 CDI、Spring 等依赖注入框架 纯 Spring 生态系统
依赖包需求 无需额外依赖(Java EE 环境内置) 需要 javax.inject 包(Java 9 + 为 jakarta.inject) 内置在 Spring 框架中
循环依赖处理 @Autowired 类似,构造器注入可能触发循环依赖 @Autowired 类似,需通过 @Lazy 等方式解决 支持通过三级缓存解决部分循环依赖
JNDI 支持 原生支持,通过 mappedName 参数 不直接支持,需手动配置 不直接支持,需通过 JNDI 服务实现
标准化程度 Java 官方标准,跨容器移植性高 Java 官方标准,适合标准化开发 Spring 特定实现,与框架深度耦合
错误处理机制 注入失败时抛出 NoSuchBeanDefinitionException 注入失败时抛出异常,需手动处理 提供更详细的异常类型(如 NoUniqueBeanDefinitionException)
最佳实践建议 1. 明确指定 name 参数 2. 处理 JNDI 资源 1. 配合 @Named 使用 2. 使用 Provider 处理可选依赖 1. 构造器注入优先 2. 配合 @Qualifier 处理多实现

总结:

核心差异解析

  1. 查找方式本质区别
    • @Resource 以名称为核心,适合明确知道 Bean 名称的场景
    • @Inject@Autowired 以类型为核心,适合面向接口编程
  2. 依赖强制性处理
    • Spring 的@Autowired提供更灵活的依赖控制,可通过required=false实现可选依赖
    • Java 标准注解需通过额外机制(如Provider)处理可选依赖
  3. 多实现场景处理
    • @Resource通过name/type参数直接指定
    • @Inject配合@Named实现名称匹配
    • @Autowired通过@Qualifier@Primary解决歧义

适用场景建议

  • Java EE 兼容项目:优先使用@Resource@Inject,确保跨容器移植性
  • 纯 Spring 项目:推荐使用@Autowired,充分利用 Spring 特性(如required参数、@Primary
  • 跨框架开发:使用@Inject+@Named,保证代码在 Spring、CDI 等不同容器中的兼容性

高级特性对比

  • @ResourcemappedName参数提供 JNDI 资源注入能力,适合企业级 Java EE 环境
  • @Inject配合Provider实现延迟依赖获取,是处理可选依赖的标准方式
  • @Autowired@Primary机制提供更简洁的默认实现选择方式
特性分类 CommonAnnotationBeanPostProcessor AutowiredAnnotationBeanPostProcessor
核心职责 处理 Java 标准注解(JSR-250),如 @Resource、生命周期注解 处理 Spring 原生注解及 JSR-330 注解,如 @Autowired@Inject
支持的注解 @Resource, @PostConstruct, @PreDestroy, @Resource, @WebServiceRef @Autowired, @Inject, @Value, @Lookup
注入方式 按名称(byName)优先,字段名 / 参数名作为默认名称 按类型(byType)优先,类型匹配后通过 @Qualifier 细化名称
注入目标 字段、Setter 方法、构造方法(需显式标记) 字段、Setter 方法、构造方法、任意方法(@Autowired 标记)
JNDI 支持 原生支持,通过 mappedName 参数指定 JNDI 名称,支持 alwaysUseJndiLookup 配置 不直接支持 JNDI 注入,需通过 JndiTemplate 等工具类手动实现
生命周期注解处理 处理 @PostConstruct(初始化)和 @PreDestroy(销毁)注解 需通过 InitDestroyAnnotationBeanPostProcessor 单独处理
Java EE 兼容性 高(完全遵循 JSR-250 规范,支持 Java EE 容器如 GlassFish) 低(Spring 专有注解,需框架适配才能在 Java EE 中使用)
多 Bean 处理机制 注入时若存在多个同类型 Bean,必须通过 name/type 参数明确指定 优先通过 @Qualifier 指定名称,或通过 @Primary 标记默认实现
依赖强制性 注入失败时直接抛出异常,无 required 参数 支持 @Autowired (required=false) 实现可选依赖
处理阶段 Bean 初始化阶段(postProcessAfterInitialization) Bean 实例化后、初始化前(postProcessProperties)
循环依赖处理 @Resource 配合时,构造器注入可能触发循环依赖问题 支持通过三级缓存解决部分循环依赖场景(字段注入 / Setter 注入)
配置参数 alwaysUseJndiLookup(强制 JNDI 查找)、jndiEnvironment 等 required(依赖强制性)、annotationType(自定义注解类型)
框架集成性 可与 JSF、EJB 等 Java EE 组件无缝集成 深度集成 Spring 生态,支持 AOP、事务等特性
依赖包需求 无需额外依赖(Java EE 环境内置 javax.annotation 包) 内置在 Spring 框架中,JSR-330 支持需引入 javax.inject 包
注解优先级 @Resource 的 name 参数 > type 参数 > 字段名 @Qualifier > @Primary > 类型匹配
适用场景 1. Java EE 标准项目 2. 需要 JNDI 资源注入 3. 跨容器移植场景 1. 纯 Spring 项目 2. 面向接口编程 3. 复杂依赖关系管理
最佳实践 1. 明确指定 @Resource 的 name 参数 2. 配合 Java EE 规范使用 1. 构造器注入优先 2. 用 @Qualifier 处理多实现 3. @Value 注入配置
与其他处理器关系 可与 AutowiredAnnotationBeanPostProcessor 共存,处理不同注解 需要配合 CommonAnnotationBeanPostProcessor 实现完整功能
错误处理机制 注入失败时抛出 NoSuchBeanDefinitionException 等标准异常 提供更细化的异常类型(如 NoUniqueBeanDefinitionException)
Spring Boot 自动配置 Spring Boot 自动配置中默认启用,支持 @Resource 注解 Spring Boot 默认启用,是依赖注入的核心处理器

职责与注解支持的本质区别

  • CommonAnnotationBeanPostProcessorJava 标准注解为核心,目标是兼容 Java EE 规范,适合需要跨容器移植的项目
  • CommonAnnotationBeanPostProcessor 直接支持@PostConstruct@PreDestroy,无需额外配置
  • AutowiredAnnotationBeanPostProcessorSpring 特性为核心,提供更灵活的依赖注入控制,适合深度使用 Spring 框架的项目
  • AutowiredAnnotationBeanPostProcessor 不直接处理生命周期注解,需配合InitDestroyAnnotationBeanPostProcessor使用

注入逻辑的核心差异

graph TD
    %% @Resource 注入流程
    A[CommonAnnotationBeanPostProcessor] -->|注入流程| B[按name查找Bean]
    B --> C{name存在?}
    C -- 是 --> D[注入对应Bean]
    C -- 否 --> E[按type查找Bean]
    E --> F{唯一type?}
    F -- 是 --> D
    F -- 否 --> G[抛出异常]

    %% @Autowired 注入流程
    X[AutowiredAnnotationBeanPostProcessor] -->|注入流程| Y[按type查找Bean]
    Y --> Z{唯一type?}
    Z -- 是 --> D
    Z -- 否 --> W[按Qualifier或Primary筛选]
    W --> H{有唯一Bean?}
    H -- 是 --> D[注入对应Bean]
    H -- 否 --> G[抛出异常]

最后我们来看看这些注解的源码

@Autowired

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
*支持多种注入点,分别是构造方法注入,字段注入,方法注入(包括 Setter 方法),参数注入(如配置方法的参数),支持自定义注解组合
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
// 注解信息在运行时保留,允许反射获取
@Retention(RetentionPolicy.RUNTIME)
// 注解信息会被包含在 JavaDoc 中
@Documented
public @interface Autowired {
/**
* 指示该依赖是否为必需项。
* 默认为true,表示容器必须能解析该依赖。此时容器必须找到匹配的 Bean,否则抛出 NoSuchBeanDefinitionException
* 如果设置为false,当容器中不存在匹配的Bean时,将注入null值(对于对象类型)。集合类型可以为空集合
*
* 对于集合或数组类型的依赖,即使required为true,
* 只要容器中存在至少一个匹配类型的Bean,就不会抛出异常。
* 若容器中没有匹配的Bean,则会根据required的值决定是否抛出异常。
*/
boolean required() default true;
}

@Resource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package jakarta.annotation; // Java EE 8+ 及 Jakarta EE 版本包路径
// Java EE 7 及以下版本使用 javax.annotation 包

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 可用于类、接口或枚举,声明类级资源,允许字段注入,方法注入(通常是 Setter 方法)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
// 注解信息在运行时保留,允许反射获取
@Retention(RetentionPolicy.RUNTIME)
// 支持在同一元素上重复使用 @Resource 注解(Java 8+ 特性)
@Repeatable(Resources.class)
public @interface Resource {
/**
* 指定要注入的资源名称。
* 若指定此值,容器将按名称查找资源(byName)。
* 示例:
* @Resource(name = "userService")
*
* 若未指定此值:
* - 对于字段注入,默认为字段名
* - 对于方法注入,默认为方法名(去除 set 前缀并小写首字母)
*/
String name() default "";

/**
* 指定 JNDI 查找名称,用于直接从 JNDI 目录中获取资源。
* 此属性优先级高于 name,若指定则直接进行 JNDI 查找。
* 示例:
* @Resource(lookup = "java:comp/env/jdbc/myDataSource")
*/
String name() default "";

/**
* 指定要注入的资源类型。
* 当按名称查找失败时,容器将按此类型查找资源(byType)。
* 默认值为 Object.class,表示使用字段或方法的声明类型。
*/
Class<?> type() default Object.class;

/**
* 指定资源的认证类型,仅适用于连接工厂类资源(如 DataSource)。
* 可选值:
* - CONTAINER:容器管理认证(默认)
* - APPLICATION:应用程序管理认证
*/
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;

/**
* 指定资源是否可共享。
* 仅适用于支持共享的资源类型,如 JMS 连接工厂。
* 默认值为 true,表示资源可被多个组件共享。
*/
boolean shareable() default true;

/**
* 指定资源的映射名称,用于与外部命名环境(如 CORBA)集成。
* 此属性通常由应用服务器使用,用于将资源映射到外部 JNDI 名称。
*/
String mappedName() default "";

/**
* 资源的描述信息,用于文档目的。
* 此信息通常存储在应用服务器的管理控制台中。
*/
String description() default "";

/**
* 定义资源认证类型的枚举。
*/
public static enum AuthenticationType {
CONTAINER, // 容器管理认证(推荐)
APPLICATION // 应用程序管理认证
}
}

@Inject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package jakarta.inject; // Java EE 8+ 及 Jakarta EE 版本包路径
// Java EE 7 及以下版本使用 javax.inject 包

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 支持支持方法注入(包括传统的 Setter 方法),支持构造方法注入,支持字段注入
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
// 注解信息在运行时保留,允许反射获取,确保容器能够在运行时处理注入逻辑
@Retention(RetentionPolicy.RUNTIME)
// 注解信息会被包含在 JavaDoc 中,提高代码可读性
@Documented
public @interface Inject {
// 无参数,依赖注入行为由规范定义
}