技术背景
在Java开发中,依赖注入(DI)是一种重要的设计模式,它有助于实现松耦合的代码结构。Spring框架为依赖注入提供了强大的支持,其中 @Resource 和 @Autowired 是两个常用的注解。@Resource 是JSR - 250标准的注解,而 @Autowired 是Spring特有的注解。了解它们的区别和适用场景,对于开发者正确使用依赖注入至关重要。
实现步骤
1. 环境准备
首先,确保你的项目中已经引入了Spring框架。如果你使用Maven,可以在 pom.xml 中添加以下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>版本号</version>
</dependency>
2. 创建接口和实现类
假设我们有一个 Parent 接口和两个实现类 ActualService 和 StubbedService:
interface Parent {
void doSomething();
}
@Service("actualService")
class ActualService implements Parent {
@Override
public void doSomething() {
System.out.println("ActualService is doing something.");
}
}
@Service("stubbedService")
class StubbedService implements Parent {
@Override
public void doSomething() {
System.out.println("StubbedService is doing something.");
}
}
3. 使用 @Autowired 进行依赖注入
@Component
public class AutowiredExample {
@Autowired
@Qualifier("actualService")
private Parent parent;
public void performAction() {
parent.doSomething();
}
}
4. 使用 @Resource 进行依赖注入
@Component
public class ResourceExample {
@Resource(name = "actualService")
private Parent parent;
public void performAction() {
parent.doSomething();
}
}
核心代码
@Autowired 示例
@Autowired
@Qualifier("actualService")
private Parent parent;
@Resource 示例
@Resource(name = "actualService")
private Parent parent;
最佳实践
- 使用 @Resource 的场景
- 当需要通过名称精确匹配注入的Bean时,优先使用 @Resource。例如,在注入集合或Map类型的Bean时,@Resource 更合适,因为 @Autowired 无法正确处理类型匹配。
- 考虑到代码的可移植性,如果未来可能会使用其他依赖注入框架,@Resource 是更好的选择。
- 使用 @Autowired 的场景
- 当根据类型进行注入时,@Autowired 是一个不错的选择。可以结合 @Qualifier 来进一步缩小匹配范围。
- 对于构造函数、多参数方法的注入,@Autowired 更合适,因为 @Resource 只支持字段和单参数的setter方法。
常见问题
1. @Autowired 注入集合或Map类型的Bean失败
这是因为 @Autowired 主要基于类型进行匹配,而集合或Map类型的匹配规则不适用。可以使用 @Resource 来解决这个问题。
2. @Resource 注入时类型不匹配
如果 @Resource 注解的字段名与容器中Bean的id匹配,但类型不同,Spring会抛出
org.springframework.beans.factory.BeanNotOfRequiredTypeException。这是因为 @Resource 首先按名称匹配Bean。
3. 无法使用 @Resource 进行动态Bean注入
如果需要根据配置文件动态注入Bean,@Resource 支持使用占位符,而 @Autowired 结合 @Qualifier 不支持。例如:
@Resource(name = "${service.name}")
private Parent parent;
其中 service.name 可以在属性文件中配置。