You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用运行时抛出Curator异常崩溃,求原因分析

Spring Boot应用崩溃异常分析与修复

异常链梳理

1. 根源异常:ZooKeeper地址解析失败触发NPE

前序日志中的NullPointerException是问题起点:

2023-02-16 16:01:11,320 [main-EventThread] [17] org.apache.curator.framework.imps.CuratorFrameworkImpl:699 - Background exception was not retry-able or retry gave up 
java.lang.NullPointerException: Cannot invoke "java.net.InetAddress.getHostAddress()" because the return value of "java.net.InetSocketAddress.getAddress()" is null        
at org.apache.curator.utils.Compatibility.getHostAddress(Compatibility.java:116)        
at org.apache.curator.framework.imps.EnsembleTracker.configToConnectionString(EnsembleTracker.java:185)     
at org.apache.curator.framework.imps.EnsembleTracker.processConfigData(EnsembleTracker.java:206)        
at org.apache.curator.framework.imps.EnsembleTracker.access$300(EnsembleTracker.java:50)        
at org.apache.curator.framework.imps.EnsembleTracker$2.processResult(EnsembleTracker.java:150)     
at org.apache.curator.framework.imps.CuratorFrameworkImpl.sendToBackgroundCallback(CuratorFrameworkImpl.java:892)       
at org.apache.curator.framework.imps.CuratorFrameworkImpl.processBackgroundOperation(CuratorFrameworkImpl.java:649)     
at org.apache.curator.framework.imps.WatcherRemovalFacade.processBackgroundOperation(WatcherRemovalFacade.java:152)     
at org.apache.curator.framework.imps.GetConfigBuilderImpl$2.processResult(GetConfigBuilderImpl.java:222)        
at org.apache.zookeeper.ClientCnxn$EventThread.processEvent(ClientCnxn.java:634)        
at org.apache.zookeeper.ClientCnxn$EventThread.run(ClientCnxn.java:553)

原因:Curator解析ZooKeeper集群配置时,某个节点的InetSocketAddress.getAddress()返回null,说明配置的ZooKeeper地址无效——可能是主机名无法DNS解析、地址格式错误(如只写端口未写主机),或者集群配置返回了空地址信息。重试机制耗尽后,触发了应用关闭流程。

2. 崩溃触发点:关闭流程中执行配置刷新

后续的IllegalStateException是导致应用直接崩溃的直接原因:

2023-02-16 17:03:15,576 [Curator-TreeCache-1] [45] org.apache.curator.framework.recipes.cache.TreeCache:827 -  java.lang.IllegalStateException: Shutdown in progress       
at org.springframework.util.Assert.state(Assert.java:76)       
at org.springframework.boot.SpringApplicationShutdownHook.assertNotInProgress(SpringApplicationShutdownHook.java:166)       
at org.springframework.boot.SpringApplicationShutdownHook.registerApplicationContext(SpringApplicationShutdownHook.java:75)       
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:413)       
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)       
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:164)       
at org.springframework.cloud.context.refresh.LegacyContextRefresher.addConfigFilesToEnvironment(LegacyContextRefresher.java:78)       
at org.springframework.cloud.context.refresh.LegacyContextRefresher.updateEnvironment(LegacyContextRefresher.java:56)       
at org.springframework.cloud.context.refresh.ContextRefresher.refreshEnvironment(ContextRefresher.java:101)       
at org.springframework.cloud.context.ContextRefresher.refresh(ContextRefresher.java:94)       
at org.springframework.cloud.endpoint.event.RefreshEventListener.handle(RefreshEventListener.java:72)       
at org.springframework.cloud.endpoint.event.RefreshEventListener.onApplicationEvent(RefreshEventListener.java:61)       
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)       
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)       
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)       
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)       
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)       
at org.springframework.cloud.zookeeper.config.ConfigWatcher.childEvent(ConfigWatcher.java:118)       
at org.apache.curator.framework.recipes.cache.TreeCache.lambda$callListeners$0(TreeCache.java:810)       
at org.apache.curator.framework.listen.MappingListenerManager.lambda$forEach$0(MappingListenerManager.java:92)       
at org.apache.curator.framework.listen.MappingListenerManager.forEach(MappingListenerManager.java:89)       
at org.apache.curator.framework.listen.StandardListenerManager.forEach(StandardListenerManager.java:89)       
at org.apache.curator.framework.recipes.cache.TreeCache.callListeners(TreeCache.java:806)       
at org.apache.curator.framework.recipes.cache.TreeCache.access$1800(TreeCache.java:78)       
at org.apache.curator.framework.recipes.cache.TreeCache$2.run(TreeCache.java:908)       
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)       
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)       
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)       
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)       
at java.base/java.lang.Thread.run(Thread.java:833)

原因:应用已进入关闭流程,但ZooKeeper的TreeCache监听器仍捕获到配置节点变化,触发了Spring Cloud的配置刷新事件。刷新流程尝试注册新的ApplicationContext,而Spring的关闭钩子检测到关闭正在进行,抛出非法状态异常,直接终止应用。

修复方案

  • 修正ZooKeeper连接配置:
    • 检查spring.cloud.zookeeper.connect-string,确保每个节点格式为IP/主机名:端口,例如10.0.0.5:2181,10.0.0.6:2181
    • 验证配置的主机名可正常解析(使用ping或nslookup测试),避免DNS解析失败导致地址为空
  • 优化Curator重试与关闭逻辑:
    • 调整Curator的重试策略(如增加重试次数、延长间隔),避免因短暂连接异常触发应用关闭
    • 在应用关闭阶段禁用ZooKeeper配置监听器,阻止刷新事件触发;或配置Spring Cloud刷新机制在关闭时跳过执行
  • 版本升级修复已知bug:
    • 检查Spring Cloud Zookeeper与Curator版本兼容性,部分旧版本存在集群地址解析的bug,升级至稳定匹配版本(例如Spring Cloud 2022.0.x搭配Curator 5.2.1)

内容的提问来源于stack exchange,提问作者Chetan Krishna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 06:52:48