1. 程式人生 > 程式設計 >總結一次型別轉換異常的解決

總結一次型別轉換異常的解決

      先說下本人是1年外包狗,正在學習的路上摸爬滾打。週五在和其他系統進行聯調的時候,人家反饋說一呼叫我的服務流程就異常中斷了。我這裡的應用日誌一直開著,也沒看見請求進來,突然靈光一閃我怎麼忘記了伺服器日誌,開啟一看,果然報錯了,錯誤描述:java.lang.ClassCastException。再具體一看報錯的地方,這是好幾年前就寫好且在生產上執行著的元件啊,為什麼突然就出現一個型別轉換錯誤呢?

       要解決這個問題,首先說下我這的系統架構,如下圖。


呼叫流程就是請求進來伺服器到應用2,通過一個寫好的元件C將請求傳送到子系統進行處理。有人肯定會問應用1是幹嘛的,它僅僅只是用來啟動子系統的,沒有其他卵用,子系統通過應用1來掛載到伺服器上。應用2通過JNDI來呼叫子系統中的服務,此時就要通過

CProxy c=(CProxy)ctx.lookup(jndiname)來進行強轉了。CProxy就是元件C中的一個類,主要用來進行資料交換的。然後就是這個地方,出現了java.lang.ClassCastException

。說實話,看到這個錯,我很茫然,啥玩意兒,生產上不是跑著的?你現在告訴我測試環境出了問題。頓時一陣涼涼,我不會把哪個地方給搞錯了吧,擦。於是我趕緊把測試版本回退到了一個月前,呼叫老的服務,還是報錯了,此時的我是懵逼的,弱小無助。

     這塊工作內容除了我還有一位公司的多年老開發也很熟,於是我就去問他了,他負責這塊業務很多年,也有一些經驗。然而結果讓人失望,他也不會,他給的那些排查方案我一看就知道方向不對,算了,這個坑看來還是得自己填。於是乎,我就在網上開始了我的尋找答案之旅。由於這塊技術太過老舊,資源也少,週五找了一晚上也沒什麼收穫,一開始就覺得可能是伺服器升級打補丁造成的,因為生產在執行給了我一個錯覺。一夜沒有什麼進展,週六我又去公司進行測試排查問題出現的原因。首先檢查了伺服器檔案,檢查了子系統檔案,發現除了補丁包以外最後修改時間都是3年前的了。強轉異常出現在應用2中,JNDI

服務提供者是子系統,於是我去拿著相同的程式碼去子系統測試,沒有報錯。那問題肯定就是在應用2中了,可是應用2也只是用來與其他系統進行通訊用,幾年沒動過了,陷入僵局。週日繼續加班,這裡說下型別轉換異常在什麼情況下會發生,第一:父類引用指向的物件的型別不是子類的時候將產生java.lang.ClassCastException異常,這個大家應該都懂;第二:型別是它的型別,但是為什麼也會報錯,因為ClassLoader不一致,也會導致java.lang.ClassCastException異常。在JVM中,類只會被載入一次,類的雙親委派模型中類的載入過程這裡就不細講了,反正大概就行檢查一下有沒有被載入,沒有被載入就給委派父類載入器去載入,父類載入器載入不了才會給子類載入器載入, 貼個找的圖

                                    

我在應用2中將CProxylookup()所產生的物件的類載入器給打印出來了,發現他們是不一樣的,CProxy用的是SystemClassloader,而lookup()產生的居然是一個自定義的類載入器。另外我在子系統中也把他們的classloader列印了出來,都是用自定義類載入器載入的,而這個自定義類載入器就是子系統的。報錯的原因是已經找到了,但是我又開始疑惑了,元件C是寫在伺服器的啟動指令碼中定義的CLASSPATH環境變數中的,如果遵循雙親委派模型的規則,都應該是由SystemClassloader載入的才對。看來得翻子系統的原始碼了,於是乎又去把子系統的啟動類反編譯了來看下,發現它實現了自己的類載入器去載入指定路徑的所有jar,重點來了,它違背了雙親委派模型的原則,不再是先交由父載入器去載入,而是反轉了過來,優先使用自己的自定義類載入器去載入指定路徑的jar,如果載入不到,就會委派父載入器去載入。所以報錯的現象就可以解釋了,為什麼同一個類卻產生了不同的類載入器。那麼如何解決呢,也很簡單,只需要把元件C從子系統的載入路徑下移除,重新找個位置放就可以了,再改下指令碼中CLASSPATH載入此元件的路徑。

      其實我現在也不清楚生產這幾年是怎麼過來的,按道理來講應該會報錯,公司領導說老交易其實已經沒有交易量了,但是至少當時投產部署,測試環境測試過吧,難道沒有出現問題?我現在也很疑惑,以至於現在雖然沒有報錯了,但也懷疑自己是不是還有什麼地方沒有關注到。

最後再貼幾篇我覺得受益的classloader相關的文章。

1.檢視JVM載入的類及類載入器的方法

www.cnblogs.com/z00377750/p…

2.JNDI 詳解

wenku.baidu.com/view/81e687…

3.深入淺出ClassLoader

ifeve.com/classloader…

4.ClassLoader

www.cnblogs.com/549294286/p…

--- 2019.8.31  ps:

上線後的感悟。

作為一個小白,其實在工作中很多比較重要的任務上級都不會派給你,需要自己去不斷深挖學習技術或是業務相關的ererything,這樣才會在關鍵時刻凸顯自己的作用。這個問題解決後我特地去讓運維幫我核查了生產相關的配置,發現是正確的。從這件事也反映出工作中版本管理、環境管理的重要性,否則就會出現很多奇奇怪怪的問題,就像這次上線一樣,測試環境沒問題,生產上報錯,排查到後半夜發現是測試與生產jdk不一致導致,生產多了一個jar,導致了衝突。