java.lang.reflect.InaccessibleObjectException

Evan1024發表於2024-03-05

低版本springboot應用使用高版本JDK報以下異常:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @7a79be86

這個錯誤是由於Java的模組化系統引入的安全限制導致的。在Java 9及之後的版本中,模組系統對反射訪問進行了限制,以防止對核心Java類的不安全訪問。

錯誤訊息 java.lang.reflect.InaccessibleObjectException 指出,嘗試透過反射訪問 java.lang.ClassLoaderdefineClass 方法時失敗了,因為 java.base 模組沒有向你的應用程式所在的未命名模組(unnamed module)開放 java.lang 包。

解決方案:
1.升級依賴庫:確保你使用的所有依賴庫都是最新的,並且與你的Java版本相容。有時,庫的新版本可能已經解決了與Java模組化系統的相容性問題。
2.使用 --add-opens JVM引數:在執行應用程式時,你可以使用 --add-opens JVM引數來顯式地開啟必要的模組和包。例如,為了允許反射訪問 java.lang 包,你可以這樣執行你的應用程式:

java --add-opens java.base/java.lang=ALL-UNNAMED -jar [your-application.jar]

說明:
這個命令會告訴JVM允許所有未命名的模組(ALL-UNNAMED)透過反射訪問 java.base 模組中的 java.lang 包。請注意,使用 --add-opens 引數是一種臨時的解決方案,通常只用於開發和測試,而不是生產環境,因為它可能會破壞Java的模組化封裝和安全性。
在開發過程中,你應該儘量避免需要這種訪問的情況,或者尋找其他不依賴於反射的解決方案。如果確實需要這樣做,請確保你瞭解相關的安全風險,並在生產環境中仔細評估。

3.使用Java 8:如果你的專案不需要Java 9或更高版本的功能,並且受模組化系統的影響較大,你可以考慮使用Java 8,它不受這些限制的影響。
4.更新應用程式模組描述符:如果你的應用程式是一個模組化的應用程式(使用了 module-info.java 檔案),你可以嘗試在模組描述符中新增 requires 語句來明確要求對 java.base 模組的訪問。例如,如果你的模組依賴於 java.sql 模組來訪問資料庫功能,你可以在 module-info.java 檔案中這樣寫:

module my.module {  
    requires java.sql;  
      
    // 其他指令,如 exports, opens, uses 等  
}

在這個例子中,my.module 是你的模組名稱,requires java.sql; 表示 my.module 依賴於 java.sql 模組。

對於 java.base 模組,由於它是所有模組隱式依賴的,你不需要新增任何 requires 語句。如果你嘗試新增 requires java.base; 到你的 module-info.java 檔案中,編譯器會忽略這個語句,因為它沒有實際作用。