news 2026/7/23 11:49:09

@Resource 按字段名查找的坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@Resource 按字段名查找的坑

Spring Boot 启动失败:BeanNotOfRequiredTypeException+nacosGracefulShutdownDelegate连环报错分析

一、错误现象

应用启动时直接失败,控制台打印大量异常堆栈,主要包括两类错误:

1. 核心错误(导致启动失败)

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'assessmentIndicatorSyncJob': Injection of resource dependencies failed Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'assessmentIndicatorCalcServiceImpl': Injection of resource dependencies failed Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'tenantFrameworkService' is expected to be of type '...TenantCommonApi' but was actually of type '...TenantFrameworkServiceImpl'

2. 次生错误(Context 关闭时反复出现)

org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'nacosGracefulShutdownDelegate': Singleton bean creation not allowed while singletons of this factory are in destruction

该错误重复出现5~6 次,随后应用退出。


二、错误根因分析

2.1 定位问题代码

@ServicepublicclassAssessmentIndicatorCalcServiceImplimplementsAssessmentIndicatorCalcService{@ResourceprivateTenantCommonApitenantFrameworkService;// ← 问题在这里!// ...}

2.2@Resource注入机制

@Resource的查找顺序是:

  1. 先按 bean name(字段名)匹配
  2. 匹配不到再按类型匹配

因为字段名叫tenantFrameworkService,Spring 就去容器中找名为tenantFrameworkService的 Bean。

2.3 容器中实际存在什么?

容器中确实有一个 Bean 叫tenantFrameworkService,但它来自yudao-spring-boot-starter-biz-tenant模块:

// TenantFrameworkServiceImpl.java@RequiredArgsConstructorpublicclassTenantFrameworkServiceImplimplementsTenantFrameworkService{// 它实现的是 TenantFrameworkService 接口privatefinalTenantCommonApitenantApi;// 内部包装了 TenantCommonApi}

而代码中声明的类型是:

// TenantCommonApi.java — 这是一个 Feign 客户端接口@FeignClient(name=RpcConstants.SYSTEM_NAME)publicinterfaceTenantCommonApi{// RPC 远程调用接口CommonResult<TenantRespDTO>getTenant(@RequestParam("id")Longid);}

2.4 类型关系

类/接口类型说明
TenantCommonApiFeign 客户端接口RPC 远程调用,通过 HTTP 调用 system-server
TenantFrameworkService本地服务接口定义本地租户服务方法
TenantFrameworkServiceImpl本地服务实现类实现TenantFrameworkService内部包装了TenantCommonApi并加了 Guava 缓存

TenantFrameworkServiceImpl不实现TenantCommonApi它们是两个完全不同的类型体系。

2.5 结论

字段名声明的类型容器中实际匹配到的 Bean结果
tenantFrameworkServiceTenantCommonApiTenantFrameworkServiceImpl(类型:TenantFrameworkServiceBeanNotOfRequiredTypeException

三、Nacos 报错为什么出现?

3.1 事件链

① BeanNotOfRequiredTypeException (tenantFrameworkService 类型不匹配) ↓ ② ApplicationContext.refresh() 失败 → 调用 doClose() 清理 ↓ ③ doClose() 发布 ContextClosedEvent ↓ ④ Nacos 的 nacosGracefulShutdownDelegate 监听器收到事件 ↓ ⑤ 该监听器尝试 getBean() → 但 BeanFactory 已在销毁状态 ↓ ⑥ BeanCreationNotAllowedException: "Singleton bean creation not allowed..."

3.2 为什么重复 5~6 次?

看堆栈中间:

NamedContextFactory.destroy() ← Spring Cloud LoadBalancer 的子容器销毁 → AbstractApplicationContext.close() → doClose() 发布 ContextClosedEvent → nacosGracefulShutdownDelegate 再次尝试 getBean()

NamedContextFactory(Spring Cloud LoadBalancer)会为每个服务创建独立的子 ApplicationContext。销毁时,每个子 Context关闭都会发布ContextClosedEvent,Nacos 监听器又注册在每个子 Context 中,所以触发多次。

3.3 错误性质

错误性质原因
BeanNotOfRequiredTypeException根因@Resource字段名导致按名称匹配到错误的 Bean
BeanCreationNotAllowedException次生启动失败后关闭 Context 时,Nacos 在销毁阶段试图 getBean
Nacos 线程池/HttpClient 销毁日志正常清理容器销毁时的正常善后动作

四、解决方案

4.1 修复方法

将字段名改为不与任何 Bean 名冲突,让@Resource退化为按类型匹配

// 修改前@ResourceprivateTenantCommonApitenantFrameworkService;// ❌ 按名称匹配到 TenantFrameworkServiceImpl// 修改后@ResourceprivateTenantCommonApitenantCommonApi;// ✅ 按类型匹配到 TenantCommonApi 的 Feign Bean

同时删除无用的 import:

// 删除这行(从未使用)importcn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;

4.2 修复后的调用

// 使用处同步修改CommonResult<TenantRespDTO>commonResult=tenantCommonApi.getTenant(TenantContextHolder.getTenantId());

4.3 原理说明

字段名改为tenantCommonApi后,Spring 找不到名为tenantCommonApi的 Bean,于是退回到按类型匹配,正确匹配到 Feign 框架自动创建的TenantCommonApi代理 Bean,注入成功。


五、教训与最佳实践

5.1@Resourcevs@Autowired

注解默认匹配方式注意事项
@Resource先按 bean name,再按 type字段名会影响注入结果
@Autowired先按 type,再按 name字段名一般不影响注入(除非有多个同类型 Bean)

5.2 字段命名建议

  • 字段名不要与其他已知的 Bean 名相同,否则@Resource会按名称匹配
  • 字段名应该反映声明的类型,而不是"想要的功能"
  • 例如:TenantCommonApi类型的字段就叫tenantCommonApi,而不是tenantFrameworkService

5.3 遇到类似错误时的排查思路

  1. 找到最底层的Caused by(而非最上面的报错)
  2. BeanNotOfRequiredTypeException中的三个关键信息:
    • Bean 名'tenantFrameworkService'
    • 期望类型TenantCommonApi
    • 实际类型TenantFrameworkServiceImpl
  3. 检查字段声明是否与 Bean 名冲突
  4. 上层的 Nacos 报错通常是次生灾害,忽略即可

六、参考

  • Spring @Resource Annotation
  • Spring Cloud Nacos Graceful Shutdown
  • DefaultSingletonBeanRegistry 源码
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/23 11:46:08

Surface安装Android双系统玩音游:从期待到现实的完整体验

如果你是一个音游爱好者&#xff0c;手头正好有一台闲置的Surface设备&#xff0c;是否曾经想过把它打造成一个完美的音游专用设备&#xff1f;毕竟Surface的触控屏和便携性看起来是玩音游的理想选择。但现实往往比理想骨感得多。 我最近尝试了在Surface Pro 5上安装Android双…

作者头像 李华
网站建设 2026/7/23 11:45:25

GEO优化该不该做?广拓时代解析企业入局AI搜索的前提

企业到底适不适合做GEO优化&#xff0c;不是看别人都在做&#xff0c;也不是看服务商说得多热闹。 要看你的客户会不会在AI里搜索、比较、提问和做决策。 如果客户经常问“哪家好、怎么选、多少钱、有什么区别、有没有案例”&#xff0c;那GEO优化就有价值&#xff1b;如果企业…

作者头像 李华
网站建设 2026/7/23 11:42:11

【毕业设计】基于 Django 的高校心理健康咨询与测评服务平台 大学生心理状态监测与干预管理系统(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/23 11:42:02

【Python毕业设计】基于 Python 的在线音乐试听、收藏、评论互动系统 个性化歌单创建与音乐推荐平台(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/23 11:41:54

婚庆公司怎么获客?凡科全新1折优惠渠道:99做小程序只认餐宝盈,含零代码SAAS、AI编程、源码定制交付

婚庆公司怎么获客&#xff1f;凡科全新1折优惠渠道&#xff1a;99做小程序只认餐宝盈 摘要 对婚庆公司商家来说&#xff0c;获客难点往往不在于门店没有服务能力&#xff0c;而在于线上表达弱、承接入口散、用户看见后不容易直接成交。现在&#xff0c;餐宝盈官网 cby888.com…

作者头像 李华