@Resource 详解及详细源码展示

@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. BeanFactory 的 getBean 方法

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

五、注意事项与常见问题

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 应用。

相关推荐

365体育手机版官网 皮偌乔旗舰店

皮偌乔旗舰店

📅 10-15 👁️ 5467
365体育手机版官网 摩拜红包在哪里可以看到入口地址 摩拜单车如何提现?