@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.相同点
- 用于依赖注入:
- 都可以用来将依赖注入到组件中
- 支持字段、构造方法和 setter 注入:
- 这些注解都可以应用于字段、构造器和 setter 方法
通用用法示例:
public class MyClass {
@Resource
private MyService resourceService;
@Inject
private MyService injectService;
@Autowired
private MyService autowiredService;
}
5.区别
注解中属性的定义不同
@Resource
注解包含 7 个属性,其中最重要的是name
和type
2个属性,分别用于指定依赖注入时 Bean 的名称和类型@Inject
注解没有任何属性@Autowired
注解仅包含 1 个required
属性,表示依赖注入的属性是否允许为 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-250 | JSR-330 | Spring 特有 |
默认注入方式 | 按名称(优先)或按类型 | 按类型 | 按类型 |
可标注位置 | 字段、方法、类(不推荐) | 字段、方法、构造函数 | 构造方法、方法、方法参数、字段或者注解上 |
支持名称注入 | 是(通过 name 属性) | 否 | 是(结合 @Qualifier ) |
支持类型注入 | 是(通过 type 属性) | 是 | 是 |
是否强依赖 Spring | 否 | 否 | 是 |
默认是否必须 | 是 | 是 | 是(可通过 required=false 设置为否) |
多候选 Bean 支持 | 不支持直接处理(需结合 Spring 特性) | 不支持直接处理(需结合其他注解如 @Named ) | 支持(结合 @Qualifier 指定 Bean) |
7.使用场景建议
@Resource
:- 适用于需要按名称注入,或者希望代码与 Spring 框架解耦的场景
- 由于属于 JSR 标准,可在其他兼容容器中使用
@Inject
:- 推荐用于与 JSR-330 兼容的项目中(如同时使用 Guice 或其他 DI 容器)
- 需要按类型注入时效果最佳,按名称时需配合
@Named
@Autowired
:- 首选用于 Spring 应用程序,特别是需要 Spring 框架提供的其他特性(如
@Qualifier
、@Primary
、@Lazy
)时
- 首选用于 Spring 应用程序,特别是需要 Spring 框架提供的其他特性(如
总结
- 如果项目是标准化开发且希望与容器解耦,使用
@Resource
或@Inject
- 如果项目是 Spring 框架驱动,首选
@Autowired