Skip to content

使用 @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) 的语义,如下例所示:

java
public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Resource(name="myMovieFinder") // (1)
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}
}
kotlin
class SimpleMovieLister {

	@Resource(name="myMovieFinder") // (1)
	private lateinit var movieFinder: MovieFinder
}
  1. 这一行执行 @Resource 注入。

如果没有显式指定名称,则默认名称派生自字段名或 Setter 方法。如果是字段,则取字段名;如果是 Setter 方法,则取 Bean 属性名(Property Name)。在以下示例中,名为 movieFinder 的 Bean 将被注入到其 Setter 方法中:

java
public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Resource
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}
}
kotlin
class SimpleMovieLister {

	@set:Resource
	private lateinit var movieFinder: MovieFinder

}

::: note 注意 注解提供的名称由 CommonAnnotationBeanPostProcessor 所感知的 ApplicationContext 解析为 Bean 名称。如果你显式配置了 Spring 的 SimpleJndiBeanFactory,这些名称可以通过 JNDI 解析。但是,我们建议你依赖默认行为,并使用 Spring 的 JNDI 查找功能来保持间接级别。 :::

不显式指定名称@Resource 使用案例中(类似于 @Autowired),@Resource 会寻找主要类型的匹配项(而不是特定的命名 Bean),并解析众所周知的可解析依赖项:BeanFactoryApplicationContextResourceLoaderApplicationEventPublisherMessageSource 接口。

因此,在以下示例中,customerPreferenceDao 字段首先查找名为 "customerPreferenceDao" 的 Bean,然后回退到类型 CustomerPreferenceDao 的主要类型匹配:

java
public class MovieRecommender {

	@Resource
	private CustomerPreferenceDao customerPreferenceDao;

	@Resource
	private ApplicationContext context; // (1)

	public MovieRecommender() {
	}

	// ...
}
kotlin
class MovieRecommender {

	@Resource
	private lateinit var customerPreferenceDao: CustomerPreferenceDao


	@Resource
	private lateinit var context: ApplicationContext // (1)

	// ...
}
  1. context 字段基于已知的可解析依赖类型 ApplicationContext 进行注入。

补充教学 —— @Resource 的那些事儿

1. @Resource vs @Autowired (重点) 这是面试和实践中最常被问到的问题。它们的本质区别在于“搜索优先级”:

  • @Autowired:默认按类型 (byType) 匹配。如果类型有冲突(多个候选者),再尝试按名称 (byName) 匹配(匹配变量名,或者配合 @Qualifier)。
  • @Resource:默认按名称 (byName) 匹配。如果按名称找不到,再回退到按类型 (byType) 匹配。

2. 匹配流程图解 当 Spring 处理 @Resource(且没写 name 属性)时:

  1. 第一步:在容器中查找 ID 等于“变量名”或“属性名”的 Bean。
  2. 第二步:找到了? -> 注入 -> 完工。
  3. 第三步:没找到? -> 在容器中进行类型匹配。
  4. 第四步:恰好有一个匹配? -> 注入 -> 完工。
  5. 第五步:有多个候选? -> 会抛出异常(除非某个 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

Based on Spring Framework.