將提供一個示例Java程序,我鼓勵您從工作站上編譯并運行此示例,以正確復制和理解此類NoClassDefFoundError問題。
再談Java靜態初始值設定項
Java編程語言為您提供了“靜態”初始化變量或代碼塊的功能。 這可以通過“靜態”變量標識符或在Java類的標頭使用static {}塊來實現。 靜態初始化程序保證在JVM生命周期中只能執行一次 ,并且通過設計是線程安全的,這使其在靜態數據初始化(例如內部對象緩存,記錄器等)中的使用非常吸引人。
問題是什么? 我將再次重復,保證靜態初始化程序在JVM生命周期中只能執行一次……這意味著此類代碼在Class加載時執行,并且在您重新啟動JVM之前不會再次執行。 現在,如果當時執行的代碼(@Class加載時間)以未處理的異常終止會發生什么?
歡迎來到java.lang.NoClassDefFoundError問題案例#2!
NoClassDefFoundError問題案例2 –靜態初始化失敗
靜態初始化程序代碼失敗,再加上嘗試創建受影響的(未加載)類的新實例的連續嘗試,便會發生此類問題。
示例Java程序
以下簡單的Java程序按以下方式拆分:
–主Java程序NoClassDefFoundErrorSimulator
–受影響的Java類ClassA
– ClassA為您提供一個ON / OFF開關,使您可以復制要研究的問題類型
該程序只是試圖嘗試創建ClassA的新實例3次(一個接一個)。 它將演示靜態變量或靜態塊初始化程序的初始失敗,再加上嘗試創建受影響的類的新實例的連續嘗試,將觸發java.lang.NoClassDefFoundError。
#### NoClassDefFoundErrorSimulator.java
package org.ph.javaee.tools.jdk7.training2;/*** NoClassDefFoundErrorSimulator* @author Pierre-Hugues Charbonneau**/
public class NoClassDefFoundErrorSimulator {/*** @param args*/public static void main(String[] args) {System.out.println("java.lang.NoClassDefFoundError Simulator - Training 2");System.out.println("Author: Pierre-Hugues Charbonneau");System.out.println("http://javaeesupportpatterns.blogspot.com\n\n"); try { // Create a new instance of ClassA (attempt #1)System.out.println("FIRST attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA();} catch (Throwable any) {any.printStackTrace();} try { // Create a new instance of ClassA (attempt #2)System.out.println("\nSECOND attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA();} catch (Throwable any) { any.printStackTrace();} try { // Create a new instance of ClassA (attempt #3)System.out.println("\nTHIRD attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA();} catch (Throwable any) { any.printStackTrace();} System.out.println("\n\ndone!");}
}
#### ClassA.java
package org.ph.javaee.tools.jdk7.training2;/*** ClassA* @author Pierre-Hugues Charbonneau**/
public class ClassA {private final static String CLAZZ = ClassA.class.getName();// Problem replication switch ON/OFFprivate final static boolean REPLICATE_PROBLEM1 = true; // static variable initializerprivate final static boolean REPLICATE_PROBLEM2 = false; // static block{} initializer// Static variable executed at Class loading timeprivate static String staticVariable = initStaticVariable();// Static initializer block executed at Class loading timestatic {// Static block code execution...if (REPLICATE_PROBLEM2) throw new IllegalStateException("ClassA.static{}: Internal Error!");}public ClassA() {System.out.println("Creating a new instance of "+ClassA.class.getName()+"...");}/**** @return*/private static String initStaticVariable() {String stringData = "";if (REPLICATE_PROBLEM1) throw new IllegalStateException("ClassA.initStaticVariable(): Internal Error!");return stringData;}
}
問題重現
為了復制問題,我們將簡單地“自愿”觸發靜態初始化器代碼的失敗。 請簡單地啟用您要研究的問題類型,例如靜態變量或靜態塊初始化程序失敗:
// Problem replication switch ON (true) / OFF (false)private final static boolean REPLICATE_PROBLEM1 = true; // static variable initializerprivate final static boolean REPLICATE_PROBLEM2 = false; // static block{} initializer
現在,讓我們在兩個開關都處于OFF的情況下運行程序(兩個布爾值都為false)
##基準(正常執行)
java.lang.NoClassDefFoundError Simulator - Training 2Author: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comFIRST attempt to create a new instance of ClassA...Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA...SECOND attempt to create a new instance of ClassA...Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA...THIRD attempt to create a new instance of ClassA...Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA...done!
對于初始運行(基準),主程序能夠成功創建3個ClassA實例,而不會出現問題。
##問題再現運行(靜態變量初始化程序失敗)
java.lang.NoClassDefFoundError Simulator - Training 2Author: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comFIRST attempt to create a new instance of ClassA...java.lang.ExceptionInInitializerErrorat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:21)Caused by: java.lang.IllegalStateException: ClassA.initStaticVariable(): Internal Error!at org.ph.javaee.tools.jdk7.training2.ClassA.initStaticVariable(ClassA.java:37)at org.ph.javaee.tools.jdk7.training2.ClassA.<clinit>(ClassA.java:16)... 1 moreSECOND attempt to create a new instance of ClassA...java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassAat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:30)THIRD attempt to create a new instance of ClassA...java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassAat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:39>)done!
##問題再現運行(靜態塊初始化程序失敗)
java.lang.NoClassDefFoundError Simulator - Training 2Author: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comFIRST attempt to create a new instance of ClassA...java.lang.ExceptionInInitializerErrorat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:21)Caused by: java.lang.IllegalStateException>: ClassA.static{}: Internal Error!at org.ph.javaee.tools.jdk7.training2.ClassA.<clinit>(ClassA.java:22)... 1 moreSECOND attempt to create a new instance of ClassA...java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassAat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:30)THIRD attempt to create a new instance of ClassA...java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassAat org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:39)done!
發生了什么? 如您所見,第一次嘗試創建ClassA的新實例確實觸發了java.lang.ExceptionInInitializerError。 此異常表示我們的靜態變量&bloc的靜態初始化程序失敗,這正是我們想要實現的目標。
此時要了解的關鍵點是,此故障確實阻止了ClassA的整個類加載。 如您所見,嘗試#2和嘗試#3都生成了java.lang.NoClassDefFoundError,為什么? 好吧,因為第一次嘗試失敗了,所以可以防止ClassA的類加載。 連續嘗試在當前ClassLoader中創建ClassA的新實例的做法一遍又一遍地產生了java.lang.NoClassDefFoundError,因為在當前ClassLoader中未找到ClassA。
如您所見,在此問題上下文中,NoClassDefFoundError只是另一個問題的癥狀或后果 。 最初的問題是在靜態初始化程序代碼失敗后觸發的ExceptionInInitializerError。 這清楚地說明了使用Java靜態初始化程序時正確進行錯誤處理和記錄的重要性。
建議和解決策略
現在在下面找到我對NoClassDefFoundError問題案例2的建議和解決策略:
–檢查java.lang.NoClassDefFoundError錯誤并確定缺少的Java類
–對受影響的類執行代碼演練,并確定其是否包含靜態初始化程序代碼(變量和靜態塊) –檢查您的服務器和應用程序日志,確定是否有任何錯誤(例如ExceptionInInitializerError)源自靜態初始化程序代碼–確認后,進一步分析代碼并確定初始化程序代碼失敗的根本原因。 您可能需要添加一些額外的日志記錄以及適當的錯誤處理,以防止并更好地處理將來的靜態初始化程序代碼失敗
請隨時發表任何問題或評論。
第4部分將開始介紹與類加載器問題有關的NoClassDefFoundError問題。
參考: java.lang.NoClassDefFoundError:如何解決–第3部分,來自我們的JCG合作伙伴 Pierre-Hugues Charbonneau,位于Java EE支持模式和Java教程博客。
翻譯自: https://www.javacodegeeks.com/2012/07/javalangnoclassdeffounderror-how-to.html