故障概述
本次故障现象如下:gateway-server 网关服务在宿主机(Linux)上通过脚本或手动初始化时始终无法正常启动。具体表现为启动过程卡住、日志追踪异常、JDK 路径不匹配,甚至有时提示启动成功后却立即抛出异常崩溃。
涉及的组件相对简单:gateway-server(基于 Spring Boot 2.7.16 / Spring Cloud)、Nacos v2.2.3(Docker 部署)、一个自定义工具包 springboot.toolbox,以及一套 Shell 启动脚本。
排查结论直接说明:Nacos 本身网络、端口映射、底层连接均正常——HTTP 端口 28096 和 gRPC 端口 29096 全链路畅通。真正的病根在于两个维度的问题叠加:
- 环境与脚本配置缺陷:JDK 启动路径配置错误,指向了不存在的目录;Shell 启动脚本中的
start动作和taillog日志监控函数逻辑存在 bug,已被临时注释。 - 框架生命周期缺陷:服务在容器就绪交接时,由于自定义组件的生命周期监听逻辑编写不当,直接触发了 Spring 内部容器异常崩溃。
排查与定位过程
1. 网络层与端口映射排查
首先怀疑 Docker 容器网络隔离导致宿主机无法访问 Nacos。于是在宿主机上分别对 127.0.0.1、私网 IP(172.31.39.235)以及公网 IP 的 28096(HTTP)和 29096(gRPC)执行了 curl 和 nc 连通性测试。结果明确——全部返回 HTTP 200,TCP 握手成功。
[root@ip-172-31-39-235 gateway-server]# curl -I https://172.31.39.235:28096/nacos/ HTTP/1.1 200 OK
结论:底层网络、Docker 端口映射、防火墙/安全组配置均无问题。
2. Nacos 客户端连通性验证
随后直接运行 ja va -jar gateway-server.jar 查看详细启动日志。日志中明确显示:
2026-07-21 01:42:31.646 | INFO ... Try to connect to server on start up, server: {serverIp = '127.0.0.1', server main port = 28096}
2026-07-21 01:42:31.646 | INFO ... Success to connect to server [127.0.0.1:28096] on start up, connectionId = 1784598151416_172.19.0.1_47722
Spring Boot 客户端成功与 Nacos 服务端建立了 gRPC 长连接,配置加载和服务注册均已完成。因此,Nacos 连接本身完全正常,可排除 Nacos 故障。
3. 启动脚本与运行环境缺陷排查
那么问题是否出现在脚本管理上?使用脚本启动时,服务无法拉起来,或日志检测不到。经查发现两个问题:
- JDK 路径错误:脚本里配的 JDK 路径在服务器上根本不存在,导致通过脚本启动时直接因为找不到 Ja va 环境而失败。
- 启动动作与日志追踪缺陷:脚本的
start动作逻辑存在缺陷,而且用来监听启动状态的taillog()函数因为超时和匹配问题已被注释掉:
# 脚本中被注释的日志检查与状态判定逻辑 # timeout 5m tail -f $filename | sed -e '/Application had been ready since/q 1'
4. 最终崩溃堆栈与元凶锁定
最令人困惑的是,服务已提示 Started GatewayServerApplication 准备就绪,却紧接着抛出 Application run failed 异常,并报出容器生命周期相关错误。核心错误日志如下:
org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'internalAsyncEventBus': Singleton bean creation not allowed while singletons of this factory are in destruction
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.ja va:220)
at com.github.ja vaclub.toolbox.spring.BeanFactory.getBean(BeanFactory.ja va:41)
at springboot.toolbox.SpringBootAutoConfiguration.onApplicationEvent(SpringBootAutoConfiguration.ja va:161)
元凶最终锁定:项目引入的自定义 Starter 组件 springboot.toolbox 中的 SpringBootAutoConfiguration。该配置类在监听应用就绪/关闭生命周期事件时(onApplicationEvent 第 161 行),通过编码调用了 BeanFactory.getBean(...) 获取单例 Bean。而此时 Spring 容器正处于销毁交接边界,直接触发了 Spring 框架的防并发保护机制,导致主线程异常退出。
解决方案与整改建议
1. 修复应用层崩溃(核心修复)
最关键的修复点:检查并修改自定义组件库(或项目内部引入的 springboot.toolbox)中的 SpringBootAutoConfiguration.ja va 文件。具体措施:
- 避免在
ApplicationReadyEvent或生命周期销毁监听器中直接动态调用BeanFactory.getBean()获取非懒加载的单例 Bean。 - 如果必须获取 Bean,应改为在容器初始化阶段通过依赖注入(
@Autowired)完成,或者先判断当前容器状态是否处于活跃状态(context.isActive()),防止在销毁阶段强制索取 Bean。
2. 修复启动脚本与环境配置
- JDK 路径修正:检查并更新服务启动脚本中的
JA VA_HOME或ja va命令路径,确保指向宿主机上实际存在的可用 JDK(例如/usr/lib/jvm/ja va-1.8.0-openjdk-...)。 - 重构启动与日志检查脚本:修复并优化
start动作以及被注释的taillog()函数,确保能正确配合application.log的输出内容判断服务是否启动成功,避免因脚本逻辑过于死板导致误判。
3. 本地开发与调试最佳实践
在宿主机本地调试时,建议统一使用 127.0.0.1:28096 作为 Nacos 连接串(走标准回环网卡),避免因 Linux 内核路由策略导致使用私网 IP 自连接时产生间歇性卡顿。

