@Resource@Inject@Autowired 是 Java 中用于实现依赖注入的注解,Spring 中支持使用 @Autowired,@Resource,@Inject三个注解来实现属性的依赖注入,它们的用法和行为有相似之处,也存在一些关键差异。以下是它们的异同点分析:


1. @Resource

源码

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
@Repeatable(Resources.class)
public @interface Resource {
    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
	    CONTAINER,
	    APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}

说明

  • 所属规范javax.annotation(JSR-250)
  • 依赖注入方式:默认按名称注入,除非没有明确指定名称
  • 作用域:适用于任何受容器管理的组件(如 Spring)
  • 优先级:
    • 如果指定了 name 属性,会按名称注入
    • 如果未指定 name,则按字段名称进行匹配
    • 如果名称无法匹配,会尝试按类型匹配
  • 注意:
    • @Resource 注解默认是通过名称进行注入的,如果要基于类型进行注入,可以省略 name 属性。
    • 如果有多个 Bean 匹配注入点的类型,将抛出 UnsatisfiedDependencyException 异常。在这种情况下,需要使用 @Qualifier 注解或指定 name 属性来解决歧义。
    • @Autowired 注解是 Spring 推荐的依赖注入方式,因为它支持更多 Spring 特有的功能,如自动装配的候选策略和更丰富的配置选项。

示例

@Resource(name = "myService")  // 按名称注入
private MyService myService;

@Resource  // 按字段名或类型注入
private MyService anotherService;

// 如果只有一个DataSource类型的bean,那么可以直接注入,不需要指定name
@Resource
private DataSource dataSource;

// 当有多个DataSource类型的bean时,可以通过type属性来指定类型(尽管通常不需要)
@Resource(type = CustomDataSource.class)
private DataSource customDataSource;

2. @Inject

源码

@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {}

说明

  • 所属规范javax.inject(JSR-330)
  • 依赖注入方式:默认按类型注入,类似于 Spring 的 @Autowired
  • 作用域:通用依赖注入,不限于 Spring 框架(可与其他 DI 容器如 Guice 一起使用)
  • 额外功能:可以与 @Named 结合使用实现按名称注入
  • 注意:
    • @Inject 注解与 @Autowired 类似,但它不提供 @Autowired 的所有功能,如指定 required 属性或通过 @Qualifier 解决多个 Bean 匹配问题。
    • 在 Spring 中,通常推荐使用 @Autowired,因为它是 Spring 特有的,并且提供了更丰富的自动装配能力。
    • 如果你决定使用 @Inject,确保你的项目中包含了 javax.inject 的依赖。

示例

@Inject  // 按类型注入
private MyService myService;

@Inject
@Named("mySpecificService")  // 配合 @Named 实现按名称注入
private MyService specificService;

3. @Autowired

源码

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

说明

  • 所属规范:Spring 框架专用
  • 依赖注入方式:
    • 默认按类型注入
    • 如果有多个相同类型的 Bean,可以结合 @Qualifier 注解进行按名称注入
    • Spring 5.0 开始支持构造器、方法、字段注入中的 @Autowired(required = false)
  • 作用域:仅在 Spring 容器中可用
  • 注意:

    • 使用 @Autowired 时,如果存在多个匹配的 Bean,可以通过 @Qualifier 注解来指定注入哪一个。
    • 如果构造器、Setter 方法或者普通方法上有多个参数,每个参数都可以使用 @Autowired,Spring 容器将为每个参数注入相应的依赖。
    • 如果一个字段、构造器参数或 Setter 方法没有标注 @Autowired,Spring 容器将不会尝试自动注入,除非你在 Spring 配置中明确指定了自动装配的行为。
    • 在字段注入的情况下,如果依赖注入失败,字段将保持 null

示例

@Autowired  // 按类型注入
private MyService myService;

@Autowired
@Qualifier("mySpecificService")  // 配合 @Qualifier 按名称注入
private MyService specificService;

@Autowired(required = false)  // 非必需依赖,若找不到 Bean 不会报错
private Optional<MyService> optionalService;

4.相同点

  1. 用于依赖注入:
    • 都可以用来将依赖注入到组件中
  2. 支持字段、构造方法和 setter 注入:
    • 这些注解都可以应用于字段、构造器和 setter 方法

通用用法示例:

public class MyClass {
    @Resource
    private MyService resourceService;

    @Inject
    private MyService injectService;

    @Autowired
    private MyService autowiredService;
}

5.区别

注解中属性的定义不同

  • @Resource 注解包含 7 个属性,其中最重要的是 nametype 2个属性,分别用于指定依赖注入时 Bean 的名称和类型
  • @Inject 注解没有任何属性
  • @Autowired 注解仅包含 1required属性,表示依赖注入的属性是否允许为 null

注解的作用范围不同

  • @Resource 注解可以作用在类、字段或者方法上
  • @Inject 注解可以作用在方法、构造方法或者字段上
  • @Autowired 注解可以作用在构造方法、方法、方法参数、字段或者注解上

出处不同

  • @Resource 注解是 JDK 提供的,遵循 JSR 250 规范,定义在JDK的 rt.jar 中,无须单独引入
  • @Inject 注解是 JDK 提供的,遵循 JSR 330 规范,定义在 javax.Inject.jar 中,需要单独引入
  • @Autowired 注解是 Spring 提供的,只有 Spring IOC 容器支持

Spring中解析注解的后置处理器不同

  • @Autowired@Inject 都是使用AutowiredAnnotationBe按PostProcessor后置处理器进行处理
  • @Resource 注解则是使用 CommonAnnotationBeanPostProcessor 后置处理器进行处理

默认的装配方式不同

  • @Autowired默认是按照 byType 的方式进行装配,如果想按照 byName 的方式进行装配,需要搭配@Qualifier注解一起使用;
  • @Resource 注解默认则是按照 byName的方式进行装配的;
  • @Inject 默认是安装 byType的方式进行装配,如果想按照 byName的方式进行装配,需要搭配@Named 注解一起使用。

装配的执行流程不同

  • @Autowired@Inject注解的执行流程大致相同:
    • 默认都是先按照 byType 的方式进行匹配,如果有且仅有一个;则匹配成功;
    • 如果一个都没有匹配到,则抛出异常;
    • 如果匹配多个,则继续判断是否配置了@Qualifier注解或者@Named注解,如果配置了,则按照指定的名称进行匹配;如果没有配置,则按照属性名进行匹配;如果能够匹配到,则匹配成功,反之则抛出异常。
  • @Resource注解的执行流程:
    • 如果指定了name属性,则会根据指定的 name 去 Spring 容器中查找 Bean ,匹配不到则抛出异常;
    • 如果没有指定name,则会先判断Spring 容器是否存在当前的属性名或者方法参数名的Bean ,存在则根据该名称去获取 Bean,不存在则按照注入点的类型去匹配,如果没有匹配到或者匹配多个,就会抛出异常。

6.异同点对比表

特性@Resource@Inject@Autowired
标准JSR-250JSR-330Spring 特有
默认注入方式按名称(优先)或按类型按类型按类型
可标注位置字段、方法、类(不推荐)字段、方法、构造函数构造方法、方法、方法参数、字段或者注解上
支持名称注入是(通过 name 属性)是(结合 @Qualifier
支持类型注入是(通过 type 属性)
是否强依赖 Spring
默认是否必须是(可通过 required=false 设置为否)
多候选 Bean 支持不支持直接处理(需结合 Spring 特性)不支持直接处理(需结合其他注解如 @Named支持(结合 @Qualifier 指定 Bean)

7.使用场景建议

  1. @Resource
    • 适用于需要按名称注入,或者希望代码与 Spring 框架解耦的场景
    • 由于属于 JSR 标准,可在其他兼容容器中使用
  2. @Inject
    • 推荐用于与 JSR-330 兼容的项目中(如同时使用 Guice 或其他 DI 容器)
    • 需要按类型注入时效果最佳,按名称时需配合 @Named
  3. @Autowired
    • 首选用于 Spring 应用程序,特别是需要 Spring 框架提供的其他特性(如 @Qualifier@Primary@Lazy)时

总结

  • 如果项目是标准化开发且希望与容器解耦,使用 @Resource@Inject
  • 如果项目是 Spring 框架驱动,首选 @Autowired

人生不作安期生,醉入东海骑长鲸