如何解决java.lang.NoClassDefFoundError--第二部分

阅读更多
如何解决NoClassDefFoundError--第二部分

第一部分请看: 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();

                Stack classLoaderStack = 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中验证,确保编译和运行期都能找到此类。

你可能感兴趣的:(如何解决java.lang.NoClassDefFoundError--第二部分)