将提供一个示例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