“...)
解決項目啟動報java.lang.NullPointerException: Cannot invoke com.alibaba.nacos.client.naming.backups.FailoverDataSource.getSwitch() because the return value of com.alibaba.nacos.client.naming.backups.FailoverReactor.access$000(com.alibaba.nacos.client.naming.backups.FailoverReactor) is null問題發(fā)現(xiàn)問題解決排查方式一在本地或者測試環(huán)境模擬生產(chǎn)環(huán)境排查方式二使用命令java -jar執(zhí)行一下生產(chǎn)的包問題發(fā)現(xiàn)最近在生產(chǎn)環(huán)境啟動時報了一個錯誤束手無策因為本地和測試環(huán)境都沒有出現(xiàn)這個問題。完整的錯誤信息如圖環(huán)境如下Nacos版本Nacos2.2.3SpringCloud版本Spring Cloud 2023.0.13JDK版本17問題解決本來以為baidu能給我答案最后發(fā)現(xiàn)根本搜不到有關(guān)該錯誤的文章。然后就開始了苦逼的排查之路。排查方式一在本地或者測試環(huán)境模擬生產(chǎn)環(huán)境然后我本地搭建了一個和生產(chǎn)環(huán)境一模一樣的Nacos版本然后將配置文件改成本地的地址示例代碼如下spring:cloud:nacos:config:server-addr:127.0.0.1:8848discovery:server-addr:127.0.0.1:8848然后啟動項目未發(fā)現(xiàn)異常情況。排查方式二使用命令java -jar執(zhí)行一下生產(chǎn)的包找到從生產(chǎn)上下載的包打開cmd窗口執(zhí)行命令java-jarxxx.jar然后發(fā)現(xiàn)問題出現(xiàn)了后來我又陸續(xù)切換了好幾個分支打包后重試均出現(xiàn)該問題。神奇的很命令啟動有這個問題Idea啟動就沒這個問題。只要能復(fù)現(xiàn)問題就好辦然后就開始定位問題我把該項目的所有代碼全刪了然后打包重新運(yùn)行發(fā)現(xiàn)正常啟動沒有異常錯誤。然后就一個類一個類的刪最后定位到一個初始化Bean的方法上面示例代碼如下RestControllerpublicclassAppControllerimplementsInitializingBean{ResourceprivateEchoServiceechoService;OverridepublicvoidafterPropertiesSet()throwsException{echoService.echo(hello);}}當(dāng)我把a(bǔ)fterPropertiesSet()方法中的代碼注釋打包后啟動依舊沒有發(fā)現(xiàn)問題。最終定位在RPC接口的問題上。回過頭去看日志你會發(fā)現(xiàn)在日志中第一次出現(xiàn)錯誤的位置結(jié)合上下文基本上可以定位問題所在位置。然后再來分析為什么會出現(xiàn)這種情況在Spring Bean的afterPropertiesSet()初始化階段訪問了Nacos客戶端相關(guān)資源Nacos服務(wù)發(fā)現(xiàn)來獲取服務(wù)地址間接依賴Nacos但此時Nacos客戶端尚未完成初始化導(dǎo)致依賴的FailoverReactor等組件為null最終觸發(fā)空指針異常。雖然Nacos沒有注冊完成那為什么RPC接口卻成功響應(yīng)結(jié)果了呢Nacos服務(wù)發(fā)現(xiàn)的核心功能已臨時可用但內(nèi)部故障轉(zhuǎn)移Failover組件的初始化滯后導(dǎo)致首次調(diào)用成功后后續(xù)的故障轉(zhuǎn)移檢查觸發(fā)空指針異常。為什么該錯誤不會影響項目正常運(yùn)行Nacos客戶端的FailoverReactor故障轉(zhuǎn)移組件屬于輔助功能其初始化異常通常發(fā)生在獨(dú)立的異步線程N(yùn)acos內(nèi)部的定時任務(wù)線程每5秒執(zhí)行一次所以導(dǎo)致日志不斷增長為什么Idea啟動正常使用命令啟動就有問題兩種運(yùn)行環(huán)境下的初始化時序、類加載機(jī)制或線程調(diào)度存在差異導(dǎo)致Nacos客戶端在IDEA中 “僥幸” 先于異步Feign調(diào)用完成初始化而打包后這種時序平衡被打破。IDEA運(yùn)行默認(rèn)會添加一些調(diào)試相關(guān)的JVM參數(shù)如-agentlib:jdwp用于調(diào)試這些參數(shù)可能會減慢JVM啟動速度或禁用某些類加載 / 初始化優(yōu)化如提前編譯、類加載并行化知道問題所在和原因就可以很快解決這個問題我們可以等待所有Bean初始化完成后再去執(zhí)行對應(yīng)的方法這樣就不會出現(xiàn)容器未初始化完成的情況示例代碼如下RestControllerpublicclassAppController{ResourceprivateEchoServiceechoService;EventListener(ContextRefreshedEvent.class)// 指定監(jiān)聽的事件類型publicvoidhandleContextRefreshed(){echoService.echo(hello);System.out.println(容器就緒處理后續(xù)操作...);}}ContextRefreshedEvent是Spring框架中一個重要的容器事件當(dāng)Spring應(yīng)用上下文ApplicationContext完成初始化或刷新時觸發(fā)。它標(biāo)志著容器內(nèi)所有Bean已完成創(chuàng)建、依賴注入和初始化包括PostConstruct方法執(zhí)行完畢是監(jiān)聽容器初始化完成的核心事件。如果你的錯誤并不是該問題導(dǎo)致的就需要考慮是否是依賴導(dǎo)致檢查依賴版本或者升級Nacos客戶端解決該問題。