天天看點

玩大發了,Tomcat 8.5 更新有坑…

最近某全系統做了環境更新:

  • Tomcat 8.5.x
  • JDK 1.8.x

有個系統更新後出現沒有這個方法異常:

threw exception; nested exception is java.lang.NoSuchMethodError: 
...
...      

上線後系統起不來,這下玩大了。。。

咋一看應該是 jar 包沖突了,經過排查,果然是 jar 包沖突了,類路徑下存在了幾個不同版本類似的 jar 包,是由另外一個依賴引入進來的 compile 依賴,然後排除沖突的依賴就解決了。

那麼問題來了,既然 jar 包沖突,相同的環境,為什麼在開發環境、測試環境、預上線環境都沒有出現問題?

經過查證,那是因為 Tomcat 8 之後的 jar 包加載方式變了,8 之前是按照字母順序加載的,而 8 之後就變了,Tomcat 使用的是 File.listFiles() 方法來擷取目前下的 jar 包,加載的順序就和檔案系統傳回的順序有關,就不一定是按字母排序了。

java.io.File#listFiles() 源碼注釋:

玩大發了,Tomcat 8.5 更新有坑…

這個方法是擷取目前下的所有檔案,它不能保證按指定的順序傳回結果,特别是,不能保證按字母順序傳回。為什麼本地環境可以,可能是剛好是按字母排序的了。

那麼,這個問題的解決辦法可以是:

1)如果是沖突問題,排除沖突依賴解決 jar 包沖突或者降級到 tomcat 7 就行了,又或者是寫個腳本檢查一下包名是否有重複的包;我們剛好是有兩個 jar 包沖突了,解決沖突就正常了;

2)如果是業務問題,我們都知道 JVM 雙親委派機制,同一個類是不能重複加載的,如果業務确實需要加載多個版本的依賴,那就需要實作自己的自定義類加載器分别去加載對應的 jar 包;

關于類加載器、雙親委派機制都可以在Java技術棧公衆号往期文章找到相對應的解答。