第一部分请看: http://vipcowrie.iteye.com/blog/1561291
本文面向的是JAVA初学者,建议你们自己编译和运行例子程序。
本文包含了NoClassDefFoundError的原因分析和例子程序,并且给出了建议的处理策略。
NoClassDefFoundError 问题原因1:缺少jar包
首先最常见的原因是classpath的配置问题。例子程序:
本例子程序尝试创建一个新的CallerClassA实例,然后执行他的一个方法,此方法引用了类ReferencingClassA,本例子演示了classpath问题导致的NoClassDefFoundError ,本例子还打印了当前的classloader chain的情况,以便进一步的分析。这个打印信息对你以后分析此类问题也很有帮助的:
程序
public class NoClassDefFoundErrorSimulator { public static void main(String[] args) { System.out .println("java.lang.NoClassDefFoundError Simulator"); // Print current Classloader context System.out.println("\nCurrent ClassLoader chain: " + ClassloaderUtil.getCurrentClassloaderDetail()); // 1. Create a new instance of CallerClassA CallerClassA caller = new CallerClassA(); // 2. Execute method of the caller caller.doSomething(); System.out.println("done!"); } }
public class CallerClassA { private final static String CLAZZ = CallerClassA.class.getName(); static { System.out.println("Classloading of " + CLAZZ + " in progress..." + ClassloaderUtil.getCurrentClassloaderDetail()); } public CallerClassA() { System.out.println("Creating a new instance of " + CallerClassA.class.getName() + "..."); } public void doSomething() { // Create a new instance of ReferencingClassA ReferencingClassA referencingClass = new ReferencingClassA(); } }
public class ReferencingClassA { private final static String CLAZZ = ReferencingClassA.class.getName(); static { System.out.println("Classloading of " + CLAZZ + " in progress..." + ClassloaderUtil.getCurrentClassloaderDetail()); } public ReferencingClassA() { System.out.println("Creating a new instance of " + ReferencingClassA.class.getName() + "..."); Maps.newHashMap(); } public void doSomething() { // nothing to do... } }
打印classloader工具类:
public class ClassloaderUtil { public static String getCurrentClassloaderDetail() { StringBuffer classLoaderDetail = new StringBuffer(); StackclassLoaderStack = new Stack (); ClassLoader currentClassLoader = Thread.currentThread() .getContextClassLoader(); classLoaderDetail .append("\n-----------------------------------------------------------------\n"); // Build a Stack of the current ClassLoader chain while (currentClassLoader != null) { classLoaderStack.push(currentClassLoader); currentClassLoader = currentClassLoader.getParent(); } // Print ClassLoader parent chain while (classLoaderStack.size() > 0) { ClassLoader classLoader = classLoaderStack.pop(); // Print current classLoaderDetail.append(classLoader); if (classLoaderStack.size() > 0) { classLoaderDetail.append("\n--- delegation ---\n"); } else { classLoaderDetail.append(" **Current ClassLoader**"); } } classLoaderDetail .append("\n-----------------------------------------------------------------\n"); return classLoaderDetail.toString(); } }
正常运行:
java -classpath .;../guava-12.0.jar NoClassDefFoundError.NoClassDefFoundErrorSimulator java.lang.NoClassDefFoundError Simulator Current ClassLoader chain: ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Classloading of NoClassDefFoundError.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of NoClassDefFoundError.CallerClassA... Classloading of NoClassDefFoundError.ReferencingClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of NoClassDefFoundError.ReferencingClassA... done!
异常重现:
java -classpath . NoClassDefFoundError.NoCl java.lang.NoClassDefFoundError Simulator Current ClassLoader chain: ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Classloading of NoClassDefFoundError.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of NoClassDefFoundError.CallerClassA... Classloading of NoClassDefFoundError.ReferencingClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of NoClassDefFoundError.ReferencingClassA... Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/collect/Maps at NoClassDefFoundError.ReferencingClassA.(ReferencingClassA.java:28) at NoClassDefFoundError.CallerClassA.doSomething(CallerClassA.java:31) at NoClassDefFoundError.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.jav Caused by: java.lang.ClassNotFoundException: com.google.common.collect.Maps at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ... 3 more
发生了什么?当你在classpath中不包含guava的引用的时候,由于ReferencingClassA在运行期引用了此类,导致了classloader报告找不到此类,从而出现NoClassDefFoundError。
classloader分析
注意:
Classloading of NoClassDefFoundError.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@addbf1 --- delegation --- sun.misc.Launcher$AppClassLoader@19821f **Current ClassLoader** -------------------------
sun.misc.Launcher$AppClassLoader是系统的classloader,负责根据classpath设置在启动的时候加载应用需要的class。
sun.misc.Launcher$ExtClassLoader是扩展classloader,负责从java_home/lib/etc以及其他使用java.ext.dirs配置的目录从加载扩展java class。
从打印结果可以看出,sun.misc.Launcher$ExtClassLoader是系统classloader的实际父类。
建议处理策略
分析异常堆栈,找到缺少的java类名称,在classpath中验证,确保编译和运行期都能找到此类。