多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

@Resource详解

@Resource详解 Resource是 JSR-250 规范提供的依赖注入注解由 JDK 定义Spring 对其提供了完整支持。它和Autowired功能相似但装配规则和适用场景有明显区别。一、来源与定义Resource的全限定名是javax.annotation.ResourceJava 8 及以前或jakarta.annotation.ResourceJakarta EE 9Spring Boot 3 使用。它不属于 Spring 专有而是 Java 标准库的一部分。在 Spring Boot 3 项目中需要确保引入了jakarta.annotation-api依赖通常由spring-boot-starter自动传递。importjakarta.annotation.Resource;ServicepublicclassUserService{ResourceprivateUserDaouserDao;}二、装配规则Resource的装配顺序与Autowired相反默认按名称byName匹配。如果不指定name属性使用字段名或 setter 方法对应的属性名作为 Bean 名称。按名称找不到时回退到按类型byType匹配。如果指定了name只按名称查找不按类型。如果指定了type只按类型查找。ServicepublicclassUserService{// 字段名 userDao先按名称 userDao 查找ResourceprivateUserDaouserDao;}如果容器中只有一个UserDao类型的 Bean但它的名称不是userDaoResource会先尝试按userDao查找找不到再按类型注入。三、name 和 type 属性1. name 属性显式指定 Bean 名称只按名称匹配。Resource(nameuserDaoImpl)privateUserDaouserDao;此时容器中必须存在名称恰好为userDaoImpl的 Bean否则抛出NoSuchBeanDefinitionException。2. type 属性显式指定类型只按类型匹配。Resource(typeUserDao.class)privateUserDaouserDao;如果同类型有多个 Bean会抛出NoUniqueBeanDefinitionException。3. name 和 type 同时指定同时指定时要求容器中存在名称和类型都匹配的 Bean否则报错。四、使用位置Resource支持的位置字段Setter 方法ServicepublicclassUserService{privateUserDaouserDao;ResourcepublicvoidsetUserDao(UserDaouserDao){this.userDaouserDao;}}Resource不支持构造器注入方法参数注入Bean方法参数required false语义五、与 Autowired 的对比对比维度ResourceAutowired来源JSR-250JDKSpring 专有默认匹配先按名称再按类型先按类型再按名称指定名称name属性Qualifier指定类型type属性无需指定默认按类型required 属性不支持支持required false构造器注入不支持支持方法参数注入不支持支持Primary 支持不支持支持处理类CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessorResource更适合“按名称注入”的场景代码更简洁。Autowired功能更丰富支持构造器注入和可选依赖。六、底层处理机制Resource由CommonAnnotationBeanPostProcessor处理。它是 Spring 容器中的一个BeanPostProcessor同时负责PostConstruct、PreDestroy等 JSR-250 注解。处理时机在 Bean 生命周期的属性填充阶段populateBean()通过postProcessProperties()方法完成注入。简化流程// CommonAnnotationBeanPostProcessorpublicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){// 1. 查找 Resource 注解的元数据InjectionMetadatametadatafindResourceMetadata(beanName,bean.getClass(),pvs);// 2. 执行注入metadata.inject(bean,beanName,pvs);returnpvs;}注入时ResourceElement.getResourceToInject()会根据name和type调用beanFactory.resolveDependency()或beanFactory.getBean(name)获取目标 Bean。七、常见问题1. 找不到 BeanNoSuchBeanDefinitionException: No bean named userDao available原因字段名与 Bean 名称不一致且容器中没有该名称的 Bean。解决指定name属性或将字段名改为与 Bean 名称一致。2. 同类型多个 Bean 冲突NoUniqueBeanDefinitionException: expected single matching bean but found 2原因按名称找不到回退到按类型但同类型有多个 Bean。解决显式指定name属性。3. Spring Boot 3 中找不到 jakarta.annotation.Resource需要确认依赖dependencygroupIdjakarta.annotation/groupIdartifactIdjakarta.annotation-api/artifactId/dependencySpring Boot 3 的spring-boot-starter已经包含该依赖。4. Resource 不支持构造器注入构造器注入只能用Autowired或省略注解单构造方法时。5. 静态字段无法注入Resource不能直接注入静态字段。需要通过实例方法赋值给静态变量。八、最佳实践需要按名称注入时优先使用Resource代码比Autowired Qualifier更简洁。需要构造器注入时使用Autowired或RequiredArgsConstructor。需要可选依赖时使用Autowired(required false)。在非 Spring 环境如标准 Java EE中Resource可保持代码的可移植性。团队统一风格避免同一个项目中混用两种注解导致理解成本增加。九、总结Resource是 JSR-250 标准的依赖注入注解默认按名称匹配找不到再按类型。它支持字段和 Setter 注入不支持构造器注入和required false。底层由CommonAnnotationBeanPostProcessor处理。维度核心要点来源JSR-250jakarta.annotation.Resource默认匹配先按名称再按类型属性name名称、type类型支持位置字段、Setter不支持构造器、方法参数、required false处理类CommonAnnotationBeanPostProcessor适用场景按名称注入、非 Spring 环境选择Resource还是Autowired取决于具体场景。按名称注入用Resource更直接构造器注入和可选依赖用Autowired更灵活。理解两者的装配顺序和底层处理能帮你在实际开发中做出合适的选择。
返回列表