Spring 熱部署造成的類加載問題


如果你的項目在IDE中出現了像下面這些奇怪的錯誤

  1. object is not an instance of declaring class
    // 對象不是聲明類的實例
    
  2. java.lang.ClassCastException: com.example.A cannot be cast to com.example.A
    // A類無法轉換成A類
    
  3. 又或者是全局靜態變量莫名變為了null,前一秒才看到靜態變量被賦值了,下一秒獲取的時候就出現了空指針異常。

而且這些錯誤在使用 java -jar xx.jar 還不會出現,那么很有可能是因為你是用了 spring-boot-devtools 依賴

官方描述:

By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular .jar file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create a META-INF/spring-devtools.properties file.

默認情況下,IDE中任何打開的項目都將使用 restart classloader加載,而任何常規的.jar文件都將使用 base classloader加載。如果你在一個多模塊項目上工作,並且不是每個模塊都被導入到你的IDE中,你可能需要自定義一些東西。要做到這一點,你可以創建一個META-INF/spring-devtools.properties文件。

原因

  • 項目中的java文件,因其可能隨時被修改,為了熱部署及時生效,這些java文件對於的類會使用 org.springframework.boot.devtools.restart.classloader.RestartClassLoader 類加載器進行加載。如果同時有jar中的一些代碼使用了反射等技術使用我們項目的類時,就會使用 AppClassLoade 進行加載。造成本該是一個類的類,因被不同的類加載器加載而同時出現兩個不同的類,而出現上面的錯誤。

解決辦法

  1. 不使用 spring-boot-devtools

  2. 在resource下創建META-INF/spring-devtools.properties

    restart.exclude.companycommonlibs=排除的jar包
    restart.include.projectcommon=包含的jar包  // 使用restartClassLoader加載
    

下面是我解決這個問題的實際步驟

下面是我工作中遇到這個問題的解決思路。我的項目中出現了1和3這樣的問題,我的項目中有一個類 AppContext 類,其中有一個全局靜態變量 context

  1. 使用 debug 斷點,在 context 被賦初始值的的地方的下一行,暫停程序,使用 jmap -dump:live,format=b,file=heap-dump-1.bin pid 導出程序的堆文件,在使用 jhat heap-dump.bin 分析堆文件,此時 context 不為null

  2. 程序繼續運行,再次導堆文件進行分析,這時 context 變為了 null ,同時發現 ClassLoader 發生了變化

  3. 基本確認是因為ClassLoader變化導致的問題,再次使用 java -jar xx.jar 運行分析,感覺 RestartClassLoader 有些特殊,然后百度搜索 restartClassLoader 解決了問題

參考資料

https://my.oschina.net/heartarea/blog/788294


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM