@Resource 详解及详细源码展示

@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. BeanFactorygetBean 方法

底层通过 BeanFactory.getBean(String name, Class<T> requiredType) 方法,根据 @Resourcenametype 属性查找匹配的 Bean。


五、注意事项与常见问题

1. 名称匹配的大小写敏感

@Resourcename 属性是大小写敏感的,需与 Bean 的名称完全一致(如 mysqlDsMysqlDs 会被视为不同)。

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 名称的场景。其核心机制依赖 CommonAnnotationBeanPostProcessorBeanFactory 的协作,支持字段、方法参数等多种注入方式。理解其源码和使用场景,有助于开发者编写更灵活、可维护的 Spring 应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值