怎么解决java.lang.NoClassDefFoundError错误

前言

在平常Java开发中,咱们常常碰到java.lang.NoClassDefFoundError这样的错误,须要花费不少时间去找错误的缘由,具体是哪一个类不见了?类明明还在,为何找不到?并且咱们很容易把java.lang.NoClassDefFoundError和java.lang.ClassNotfoundException这两个错误搞混,事实上这两个错误是彻底不一样的。咱们每每花费时间去不断尝试一些其余的方法去解决这个问题,而没有真正去理解这个错误的缘由。这篇文章就是经过解决NoClassDefFoundError错误处理的经验分享来揭开NoClassDefFoundError的一些秘密。NoClassDefFoundError的错误并不是不能解决或者说很难解决,只是这种错误的表现形式很容易迷惑其余的Java开发者。下面咱们来分析下为何会发生NoClassDefFoundError这样的错误,以及怎样去解决这个错误。html

NoClassDefFoundError错误发生的缘由

NoClassDefFoundError错误的发生,是由于Java虚拟机在编译时能找到合适的类,而在运行时不能找到合适的类致使的错误。例如在运行时咱们想调用某个类的方法或者访问这个类的静态成员的时候,发现这个类不可用,此时Java虚拟机就会抛出NoClassDefFoundError错误。与ClassNotFoundException的不一样在于,这个错误发生只在运行时须要加载对应的类不成功,而不是编译时发生。不少Java开发者很容易在这里把这两个错误搞混。java

简单总结就是,NoClassDefFoundError发生在编译时对应的类可用,而运行时在Java的classpath路径中,对应的类不可用致使的错误。发生NoClassDefFoundError错误时,你能看到以下的错误日志:linux

Exception in thread "main" java.lang.NoClassDefFoundError
  •  

错误的信息很明显地指明main线程没法找到指定的类,而这个main线程可能时主线程或者其余子线程。若是是主线程发生错误,程序将崩溃或中止,而若是是子线程,则子线程中止,其余线程继续运行。框架

NoClassDefFoundError和ClassNotFoundException区别

咱们常常被java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError这两个错误迷惑不清,尽管他们都与Java classpath有关,可是他们彻底不一样。NoClassDefFoundError发生在JVM在动态运行时,根据你提供的类名,在classpath中找到对应的类进行加载,但当它找不到这个类时,就发生了java.lang.NoClassDefFoundError的错误,而ClassNotFoundException是在编译的时候在classpath中找不到对应的类而发生的错误。ClassNotFoundException比NoClassDefFoundError容易解决,是由于在编译时咱们就知道错误发生,而且彻底是因为环境的问题致使。而若是你在J2EE的环境下工做,而且获得NoClassDefFoundError的异常,并且对应的错误的类是确实存在的,这说明这个类对于类加载器来讲,多是不可见的。this

怎么解决NoClassDefFoundError错误

根据前文,很明显NoClassDefFoundError的错误是由于在运行时类加载器在classpath下找不到须要加载的类,因此咱们须要把对应的类加载到classpath中,或者检查为何类在classpath中是不可用的,这个发生可能的缘由以下:spa

  1. 对应的Class在java的classpath中不可用
  2. 你可能用jar命令运行你的程序,但类并无在jar文件的manifest文件中的classpath属性中定义
  3. 可能程序的启动脚本覆盖了原来的classpath环境变量
  4. 由于NoClassDefFoundError是java.lang.LinkageError的一个子类,因此可能因为程序依赖的原生的类库不可用而致使
  5. 检查日志文件中是否有java.lang.ExceptionInInitializerError这样的错误,NoClassDefFoundError有多是因为静态初始化失败致使的
  6. 若是你工做在J2EE的环境,有多个不一样的类加载器,也可能致使NoClassDefFoundError

下面咱们看一些当发生NoClassDefFoundError时,咱们该如何解决的样例。操作系统

NoClassDefFoundError解决示例

  • 当发生因为缺乏jar文件,或者jar文件没有添加到classpath,或者jar的文件名发生变动会致使java.lang.NoClassDefFoundError的错误。
  • 当类不在classpath中时,这种状况很难确切的知道,但若是在程序中打印出System.getproperty(“java.classpath”),能够获得程序实际运行的classpath
  • 运行时明确指定你认为程序能正常运行的 -classpath 参数,若是增长以后程序能正常运行,说明原来程序的classpath被其余人覆盖了。
  • NoClassDefFoundError也可能因为类的静态初始化模块错误致使,当你的类执行一些静态初始化模块操做,若是初始化模块抛出异常,哪些依赖这个类的其余类会抛出NoClassDefFoundError的错误。若是你查看程序日志,会发现一些java.lang.ExceptionInInitializerError的错误日志,ExceptionInInitializerError的错误会致使java.lang.NoClassDefFoundError: Could not initialize class,以下面的代码示例:
/**
 * Java program to demonstrate how failure of static initialization subsequently cause
 * java.lang.NoClassDefFoundError in Java.
 * @author Javin Paul
 */
public class NoClassDefFoundErrorDueToStaticInitFailure {

    public static void main(String args[]){

        List<User> users = new ArrayList<User>(2);

        for(int i=0; i<2; i++){
            try{
            users.add(new User(String.valueOf(i))); //will throw NoClassDefFoundError
            }catch(Throwable t){
                t.printStackTrace();
            }
        }         
    }
}

class User{
    private static String USER_ID = getUserId();

    public User(String id){
        this.USER_ID = id;
    }
    private static String getUserId() {
        throw new RuntimeException("UserId Not found");
    }     
}

Output
java.lang.ExceptionInInitializerError
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
Caused by: java.lang.RuntimeException: UserId Not found
    at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41)
    at testing.User.<clinit>(NoClassDefFoundErrorDueToStaticInitFailure.java:35)
    ... 1 more
java.lang.NoClassDefFoundError: Could not initialize class testing.User
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)


Read more: http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html#ixzz3dqtbvHDy
  •  
  • 因为NoClassDefFoundError是LinkageError的子类,而LinkageError的错误在依赖其余的类时会发生,因此若是你的程序依赖原生的类库和须要的dll不存在时,有可能出现java.lang.NoClassDefFoundError。这种错误也可能抛出java.lang.UnsatisfiedLinkError: no dll in java.library.path Exception Java这样的异常。解决的办法是把依赖的类库和dll跟你的jar包放在一块儿。
  • 若是你使用Ant构建脚原本生成jar文件和manifest文件,要确保Ant脚本获取的是正确的classpath值写入到manifest.mf文件
  • Jar文件的权限问题也可能致使NoClassDefFoundError,若是你的程序运行在像linux这样多用户的操做系统种,你须要把你应用相关的资源文件,如Jar文件,类库文件,配置文件的权限单独分配给程序所属用户组,若是你使用了多个用户不一样程序共享的jar包时,很容易出现权限问题。好比其余用户应用所属权限的jar包你的程序没有权限访问,会致使java.lang.NoClassDefFoundError的错误。
  • 基于XML配置的程序也可能致使NoClassDefFoundError的错误。好比大多数Java的框架像Spring,Struts使用xml配置获取对应的bean信息,若是你输入了错误的名称,程序可能会加载其余错误的类而致使NoClassDefFoundError异常。咱们在使用Spring MVC框架或者Apache Struts框架,在部署War文件或者EAR文件时就常常会出现Exception in thread “main” java.lang.NoClassDefFoundError。
  • 在有多个ClassLoader的J2EE的环境中,很容易出现NoClassDefFoundError的错误。因为J2EE没有指明标准的类加载器,使用的类加载器依赖与不一样的容器像Tomcat、WebLogic,WebSphere加载J2EE的不一样组件如War包或者EJB-JAR包。关于类加载器的相关知识能够参考这篇文章类加载器的工做原理.net

    总结来讲,类加载器基于三个机制:委托、可见性和单一性,委托机制是指将加载一个类的请求交给父类加载器,若是这个父类加载器不可以找到或者加载这个类,那么再加载它。可见性的原理是子类的加载器能够看见全部的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。单一性原理是指仅加载一个类一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类。如今假设一个User类在WAR文件和EJB-JAR文件都存在,而且被WAR ClassLoader加载,而WAR ClassLoader是加载EJB-JAR ClassLoader的子ClassLoader。当EJB-JAR中代码引用这个User类时,加载EJB-JAR全部class的Classloader找不到这个类,由于这个类已经被EJB-JAR classloader的子加载器WAR classloader加载。线程

    这会致使的结果就是对User类出现NoClassDefFoundError异常,而若是在两个JAR包中这个User类都存在,若是你使用equals方法比较两个类的对象时,会出现ClassCastException的异常,由于两个不一样类加载器加载的类没法进行比较。3d

  • 有时候会出现Exception in thread “main” java.lang.NoClassDefFoundError: com/sun/tools/javac/Main 这样的错误,这个错误说明你的Classpath, PATH 或者 JAVA_HOME没有安装配置正确或者JDK的安装不正确。这个问题的解决办法时从新安装你的JDK。

  • Java在执行linking操做的时候,也可能致使NoClassDefFoundError。例如在前面的脚本中,若是在编译完成以后,咱们删除User的编译文件,再运行程序,这个时候你就会直接获得NoClassDefFoundError,而错误的消息只打印出User类的名称。
java.lang.NoClassDefFoundError: testing/User
    at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
  •  

如今咱们知道要怎样去面对NoClassDefFoundError异常并解决它了。

参考文章:

how classpath work in java

3 ways to solve java.lang.NoClassDefFoundError in Java J2EE

When a class is loaded and initialized in JVM

类加载器的工做原理