java.lang.NoClassDefFoundError:could not initial class xxxxxxxxx

(转载)http://www.voidcn.com/blog/wangjun5159/article/p-6223131.html

API

当出现这个异常时,我的第一反应是,它跟ClassNotFoundException有什么不同。为了找到确切的答案我查看了它的api,

/*Thrown if the Java Virtual Machine or a ClassLoader instance 
* tries to load in the definition of a class (as part of a normal method call 
* or as part of creating a new instance using the new expression) 
* and no definition of the class could be found. 
*


* The searched-for class definition existed when the currently 
* executing class was compiled, but the definition can no longer be 
* found.

翻译过来就是,在调用方法或者new创建实例时,java虚拟机或者类加载器试图载入类定义,但是找不到类定义;编译当前执行类时,类是存在,但是现在找不到了

分析

出了这个异常后,自然而然想到jar包中可能没有这个类,查看包中发现有这个类!如果没有这个类会抛出ClassNotFoundException; 
继续深究,发现异常信息是java.lang.NoClassDefFoundError: could not initialize class:xxxxxx,自然而然想到java的类加载机制。 
java类加载陆续经历,加载、验证、准备、解析、初始化等阶段,而上述异常表明是在初始化阶段出了问题。 
在类的初始化阶段,执行方法(由编译器加入),它收集了静态代码块、静态变量赋值,收集顺序与源码中的顺序一致,执行完方法后,才完成类的加载。如果过程中出现错误,会导致类初始化失败。 
基于这个原理,再回头看代码,发现类中的静态代码块中出现了异常,但是没有catch,导致出现异常。

解决方案

将static中的代码,try catch,并存入log,不妨碍类的加载,不然就会出现NoClassDefFoundError。 
比如

static{

        try{
            //static initialize code
        }catch(Exception e){

        }
    }

疑问

在tomcat启动中,只报出NoClassDefFoundError,没有具体原因;但在javase中有根本原因,猜测是tomcat类加载器catch了异常细节,只给出了上层异常信息;

JavaSE做的测试

public class A {

    static {
        boolean flag = true;
        if (flag) {
            throw new RuntimeException("初始化类失败");
        }
    }

    public static void main(String[] args) {
    }
}

控制台打印

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: 初始化类失败
    at testmaven.test.A.(A.java:8)

结论

再回过头来看NoClassDefFoundError的API说明,就能看懂了;

  • classnotfoundexception,是找不到类的二进制流,比如从jar中、网络中,找不到这个类;
  • NoClassDefFoundError,类路径中有类,由于加载时静态代码块或者静态变量出现异常导致。对静态代码块进行try catch处理。








记一次上线的NoClassDefFoundError异常

http://afredlyj.github.io/posts/noclassdeffounderror.html

上周同事上线一个dubbo服务,当然上线之前经过功能测试和压测,都是没有问题的,上线之后服务能够启动,但是无法提供服务,报NoClassDefFoundError,后面临时加上日志,才找到问题。

现象

这个新上线的服务分别向两个业务提供服务,一个是http服务,另外一个是rpc服务,处于性能考虑,将前者的http服务也改为rpc,又为了方便管理,统一了facade接口,所以出现问题时的第一直觉是这个接口jar包有问题,导致接口不兼容,后来证实时错误的。部分异常日志如下:


java.lang.NoClassDefFoundError: Could not initialize class com.x.x.XManager
        at com.x.dubbo.impl.XDubboImpl.transferSso(XDubboImpl.java:40) ~[YYY.20150414.jar:na]
        at com.alibaba.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java) ~[na:2.5.3]
        at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46) ~[dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72) ~[dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53) ~[dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78) ~[dubbo-2.5.3.jar:2.5.3]
        at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) [dubbo-2.5.3.jar:2.5.3]

平时遇到比较多的是ClassNotFoundExceptionNoClassDefFoundError接触比较少,这次为什么遇到,比较奇怪。

分析

出问题之后,特意查了一下以上两种异常的区别,javadoc解释如下:

NoClassDefFoundError

Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found. The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

ClassNotFoundException

Thrown when an application tries to load in a class through its string name using:

  • The forName method in class Class.
  • The findSystemClass method in class ClassLoader .
  • The loadClass method in class ClassLoader.

but no definition for the class with the specified name could be found.

两者的区别在于,后者是缺少.class文件,比如缺少依赖的jar包,而前者并不缺少依赖包,只是找不到类定义,如果出现程序包了后面的异常,一般需要检查类的初始化部分,比如类属性定义和static代码块,如果找不到问题,建议在类初始化代码块中添加try-catch,并将异常打印出来,这样定位问题就简单一些。

ok,分析之后就是证实,经过查看代码,确认线上的XManager类有static代码块,加上try-catch之后放到线上,并放少量流量,查看日志发现几个问题:

  1. XManager提供静态方法,它的属性都是静态变量;
  2. 属性在static代码块中初始化;
  3. 属性的初始化依赖由Spring加载的context。

服务启动运行main方法,main函数启动dubbo服务,能接收rpc服务,Spring加载bean,提供netty服务,由于主线程Spring初始化比较慢,导致rpc请求到达时,部分bean没有完成初始化context为空,从而导致static初始化失败,最后导致事故。

找到事故原因,处理起来就比较简单了,选了一种简单易行的办法,将XManager改为单例,并有Spring管理,依赖的属性交由Spring注入,这样就能解决这个问题。

复现

在分析完成之后,需要复现异常,证实上面的部分推测,测试源码。







http://afredlyj.github.io/posts/noclassdeffounderror.html

java.lang.NoClassDefFoundError:无法初始化XXX - 共享笔记

问题描述

public class PropHolder {
  public static Properties prop;

  static {
    //code for loading properties from file
  }
}

// Referencing the class somewhere else:
Properties prop = PropHolder.prop;

class PropHolder是我自己的一个类。该类驻留在主类的相同JAR文件中。所以这不应该是因为任何JAR从类路径中丢失。

当我查看jar tf myjarfile的JAR文件时,我可以看到列出的PropHolder.class

Btw:我的本地机器上的代码正常运行。但是当我将一些脚本部署到Linux服务器上时,无法正常工作。所以我认为这不是代码的问题。但是由于某种原因部署过程很难跟踪。

可能是什么问题呢?

最佳解决方案

我最好的打赌是这里有一个问题:

  static {
    //code for loading properties from file
  }

它会出现一些未捕获的异常发生并传播到实际的ClassLoader尝试加载该类。我们需要一个堆栈跟踪来确认。

或者是在创建PropHolder.prop静态变量时发生。

次佳解决方案

你正在得到一个java.lang.NoClassDefFoundError,这并不意味着你的班级缺少(在这种情况下你会得到一个java.lang.ClassNotFoundException)。当尝试读取类时,ClassLoader会读取类定义时遇到错误。

将一个try /catch放在静态初始化程序中并查看异常。如果你读了一些文件,它与你的本地环境不同,很有可能是问题的原因(也许文件找不到,没有权限等)。

第三种解决方案

NoClassDefFoundError并没有给出很多关于静态块内出了什么问题的线索。这是一个很好的习惯,在静态{…}初始化代码中总是有一个像这样的块。

static {
  try {

    ... your init code here

  } catch (Throwable t) {
    LOG.error("Failure during static initialization", t);
    throw t;
  }
}

参考文献

  • java.lang.NoClassDefFoundError: Could not initialize class XXX

注:本文内容整合自google/baidu/bing辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:gxnotes#qq.com(#替换为@)。





你可能感兴趣的:(Android学习)