@Resource 是 Java EE(现 Jakarta EE)标准中用于依赖注入的注解(JSR-250),Spring 框架完全支持该注解。它通过名称匹配或类型匹配自动注入依赖的 Bean,适用于需要显式指定依赖名称或跨框架集成的场景。以下从注解定义、源码解析、核心功能、使用场景及注意事项展开详细说明。
一、@Resource 注解的定义与源码解析
@Resource 位于 javax.annotation 包(Jakarta EE 9+ 后移至 jakarta.annotation),其源码定义如下(简化版):
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Resource {
/**
* 资源名称(用于匹配 Bean 的名称,默认空)
*/
String name() default "";
/**
* 资源类型(用于匹配 Bean 的类型,默认空)
*/
Class> type() default Object.class;
}
关键属性说明:
name:指定要注入的 Bean 名称(默认空,此时按类型匹配)。type:指定要注入的 Bean 类型(默认 Object.class,此时按名称匹配)。
二、核心功能:依赖注入的匹配规则
@Resource 的核心功能是通过名称匹配或类型匹配定位目标 Bean,其匹配规则如下:
1. 优先按名称匹配
若 name 属性显式指定(非空),则优先查找名称完全匹配的 Bean(不区分大小写?不,Spring 中 Bean 名称是大小写敏感的)。
2. 名称不匹配时按类型匹配
若 name 为空或未找到匹配的 Bean,则按 type 属性指定的类型查找匹配的 Bean(支持继承关系,如接口与实现类)。
3. 无匹配时的行为
若既无名称匹配也无类型匹配的 Bean,且 @Resource 未标记为可选(Spring 中无 required 属性),则抛出 NoSuchBeanDefinitionException。
三、典型使用场景与示例
1. 按名称注入(最常用)
当容器中存在多个同类型 Bean 时,通过 name 属性指定要注入的 Bean 名称:
示例:
// 配置类:定义两个同类型的 Bean(名称分别为 "mysqlDs" 和 "oracleDs")
@Configuration
public class DataSourceConfig {
@Bean("mysqlDs")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().url("jdbc:mysql://...").build();
}
@Bean("oracleDs")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().url("jdbc:oracle:...").build();
}
}
// 服务类:按名称注入 "mysqlDs"
@Service
public class DataService {
@Resource(name = "mysqlDs") // 显式指定名称
private DataSource dataSource;
public void connect() {
System.out.println("连接到 MySQL:" + dataSource); // 输出 MySQL 数据源
}
}
2. 按类型注入(无同名 Bean 时)
当容器中只有一个匹配类型的 Bean 时,name 可留空,@Resource 自动按类型匹配:
示例:
@Service
public class UserService {
// 无 name 属性,按类型匹配唯一的光纤 UserService
@Resource
private UserService userService; // 错误!不能注入自身(循环依赖)
// 正确示例:注入同类型的另一个 Bean(假设存在)
@Resource
private UserRepository userRepository; // 假设 UserRepository 是唯一匹配的 Bean
}
3. 解决多候选 Bean 的歧义
当存在多个同类型 Bean 且未显式指定 name 时,@Resource 会抛出 NoUniqueBeanDefinitionException。此时需通过 name 明确指定:
示例:
// 配置类:两个同类型的 PaymentService
@Configuration
public class PaymentConfig {
@Bean
public PaymentService alipayService() {
return new AlipayService();
}
@Bean
public PaymentService wechatPayService() {
return new WechatPayService();
}
}
// 服务类:未指定 name 时抛出异常(多候选)
@Service
public class OrderService {
@Resource // 错误!存在两个 PaymentService,无法确定注入哪一个
private PaymentService paymentService;
}
// 正确方式:通过 name 指定
@Service
public class OrderService {
@Resource(name = "alipayService") // 明确指定
private PaymentService paymentService;
}
4. 注入方法参数
@Resource 可标注在方法参数上,Spring 会调用该方法并注入参数:
示例:
@Service
public class LogService {
private Logger logger;
// 方法参数注入(@Resource 标注在参数上)
@Resource
public void setLogger(Logger logger) {
this.logger = logger;
}
public void log(String message) {
logger.info(message);
}
}
5. 与 @Autowired 的对比
特性@Resource@Autowired来源JSR-250 标准(跨框架)Spring 自定义注解匹配优先级先名称,后类型先类型,后名称(@Qualifier 辅助)可选性不支持(无 required 属性)支持(required 默认 true)多候选处理必须显式 name 匹配可通过 @Qualifier 或 @Primary 解决适用场景跨框架集成、显式名称匹配Spring 项目内部依赖注入
四、源码实现细节与关键类
1. CommonAnnotationBeanPostProcessor
Spring 处理 JSR-250 注解(如 @Resource、@PostConstruct)的核心类,继承自 InstantiationAwareBeanPostProcessorAdapter。其主要方法包括:
postProcessProperties:处理字段、方法参数的注入。postProcessBeforeInstantiation:处理构造器注入(通过 ConstructorResolver)。
2. ResourceLoader
CommonAnnotationBeanPostProcessor 依赖 ResourceLoader 查找和加载 Bean。对于 Spring 容器,ResourceLoader 通常是 DefaultResourceLoader,负责从 BeanFactory 中获取 Bean。
3. BeanFactory 的 getBean 方法
底层通过 BeanFactory.getBean(String name, Class
五、注意事项与常见问题
1. 名称匹配的大小写敏感
@Resource 的 name 属性是大小写敏感的,需与 Bean 的名称完全一致(如 mysqlDs 与 MysqlDs 会被视为不同)。
2. 避免循环依赖
@Resource 无法直接解决循环依赖(与 @Autowired 类似)。若两个 Bean 相互依赖,需通过以下方式解决:
使用 @Lazy 延迟初始化。改为构造器注入(Spring 4.3+ 支持构造器注入的循环依赖)。
3. 不支持可选依赖
@Resource 没有 required 属性,若依赖的 Bean 不存在,Spring 会直接抛出 NoSuchBeanDefinitionException。若需可选依赖,需结合 @Autowired(required = false)(不推荐混合使用)。
4. 与 @ComponentScan 的协同
@Resource 注入的 Bean 需被 @ComponentScan 扫描到(或通过 @Bean 显式声明),否则会因找不到 Bean 而报错。
5. 性能优化
避免在 @Resource 中使用复杂的名称匹配(如通配符),可能导致额外的查找开销。对于高频访问的 Bean,可通过 @Primary 标记主候选,减少运行时匹配成本。
六、总结
@Resource 是 Java EE 标准的依赖注入注解,通过名称优先、类型次之的匹配规则实现依赖注入,适用于跨框架集成或需要显式指定 Bean 名称的场景。其核心机制依赖 CommonAnnotationBeanPostProcessor 和 BeanFactory 的协作,支持字段、方法参数等多种注入方式。理解其源码和使用场景,有助于开发者编写更灵活、可维护的 Spring 应用。
