使用 @Resource 进行注入 (Injection with @Resource)
Spring 还支持使用 JSR-250 的 @Resource 注解 (jakarta.annotation.Resource) 标注在字段或 Bean 属性的 Setter 方法上。这是 Jakarta EE 中的常见模式:例如,在 JSF 管理的 Bean 和 JAX-WS 端点中。Spring 也为 Spring 管理的对象支持这种模式。
@Resource 接受一个 name 属性。默认情况下,Spring 将该值解释为要注入的 Bean 名称。换句话说,它遵循按名称 (by-name) 的语义,如下例所示:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder") // (1)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}class SimpleMovieLister {
@Resource(name="myMovieFinder") // (1)
private lateinit var movieFinder: MovieFinder
}- 这一行执行
@Resource注入。
如果没有显式指定名称,则默认名称派生自字段名或 Setter 方法。如果是字段,则取字段名;如果是 Setter 方法,则取 Bean 属性名(Property Name)。在以下示例中,名为 movieFinder 的 Bean 将被注入到其 Setter 方法中:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}class SimpleMovieLister {
@set:Resource
private lateinit var movieFinder: MovieFinder
}::: note 注意 注解提供的名称由 CommonAnnotationBeanPostProcessor 所感知的 ApplicationContext 解析为 Bean 名称。如果你显式配置了 Spring 的 SimpleJndiBeanFactory,这些名称可以通过 JNDI 解析。但是,我们建议你依赖默认行为,并使用 Spring 的 JNDI 查找功能来保持间接级别。 :::
在不显式指定名称的 @Resource 使用案例中(类似于 @Autowired),@Resource 会寻找主要类型的匹配项(而不是特定的命名 Bean),并解析众所周知的可解析依赖项:BeanFactory、ApplicationContext、ResourceLoader、ApplicationEventPublisher 和 MessageSource 接口。
因此,在以下示例中,customerPreferenceDao 字段首先查找名为 "customerPreferenceDao" 的 Bean,然后回退到类型 CustomerPreferenceDao 的主要类型匹配:
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context; // (1)
public MovieRecommender() {
}
// ...
}class MovieRecommender {
@Resource
private lateinit var customerPreferenceDao: CustomerPreferenceDao
@Resource
private lateinit var context: ApplicationContext // (1)
// ...
}context字段基于已知的可解析依赖类型ApplicationContext进行注入。
补充教学 —— @Resource 的那些事儿
1. @Resource vs @Autowired (重点) 这是面试和实践中最常被问到的问题。它们的本质区别在于“搜索优先级”:
- @Autowired:默认按类型 (byType) 匹配。如果类型有冲突(多个候选者),再尝试按名称 (byName) 匹配(匹配变量名,或者配合
@Qualifier)。 - @Resource:默认按名称 (byName) 匹配。如果按名称找不到,再回退到按类型 (byType) 匹配。
2. 匹配流程图解 当 Spring 处理 @Resource(且没写 name 属性)时:
- 第一步:在容器中查找 ID 等于“变量名”或“属性名”的 Bean。
- 第二步:找到了? -> 注入 -> 完工。
- 第三步:没找到? -> 在容器中进行类型匹配。
- 第四步:恰好有一个匹配? -> 注入 -> 完工。
- 第五步:有多个候选? -> 会抛出异常(除非某个 Bean 标注了
@Primary)。
3. 为什么有人更喜欢 @Resource?
- 标准驱动:
@Resource是官方的 JSR-250 / Jakarta EE 标准注解,而@Autowired是 Spring 特有的。理论上,使用标准注解的代码在向其他 IoC 容器迁移时压力更小。 - 语义清晰:如果你明确想通过 Bean ID 注入,写
@Resource(name="userService")比写@Autowired @Qualifier("userService")更加直观。
4. 局限性:不支持构造器注入 这是 @Resource 的硬伤:
@Autowired:可以标注在构造函数、方法、字段上。- @Resource:只能标注在字段 (Field) 或单参数的 Setter 方法上。 这意味着如果你追求“构造器注入”来保证依赖的不可变性,
@Resource将无法派上用场。
5. 总结建议
- 如果你追求 Jakarta EE 标准,且经常需要按 ID 注入,用
@Resource。 - 如果你遵循 Spring 推荐的最佳实践(如构造器注入),或者需要复杂的泛型、数组注入,请稳稳地使用
@Autowired。