在JAVA开发中,main线程中抛出java.lang.NoClassDefFoundError是一个很是广泛且比较难解决的问题。解决这个问题的复杂性主要取决于你的软件大小和中间件部署状况,尤为要考虑在应用中出现的数量众多的classloader的状况。
本文将从一个比较高的角度看这个问题,主要是介绍java classloader机制。 java
那么,什么是java.lang.NoClassDefFoundError呢?
咱们先简单的看一下这个问题,这个runtime异常是JVM抛出的,当JVM发现一个classloader试图去Load一个class,而此class在当前的classloader tree中找不到的时候,就会抛出此异常。
很明显,这个问题是运行期的问题,在编译期一切正常。
那么,解决起来很简单,就是把jar包放到classpath下不就好了么?
ok,到这里还不行,这个问题解决起来不是那么容易的,在运行期的程序classpath中加入缺乏的jar包仅仅是一种解决方法。关键是,咱们必须掌握此种异常的根本缘由,之后解决此问题就能够以不变应万变。web
如今,先记住,此问题不必定是因为在classpath中缺乏class的定义。
java classloader概述
在深刻分析以前,咱们必须掌握java classloader的基本原理。class loader是一个java对象,它负责load全部的class,负责查找、加载、生成一个class的基本定义信息。classloader自身采用了委托代理机制来查询class,每个classloader的实例都有一个父classloader,因此,当一个应用的classloader去加载class A的时候,首先发生的事情是classloader委托其父classloader去加载class A,通过一串链式查找后,最终任务会落在JVM的系统启动classloader上。
那哪里会出问题?当你指望你的应用classloader能加载class A,可是当class A被其任意一个父classloader查询到并加载,那么就可能会出现java.lang.NoClassDefFoundError。当全部的父classloader都找不到class A的时候,才会由应用本身的classloader尝试加载。 app
本文包含了NoClassDefFoundError的缘由分析和例子程序,而且给出了建议的处理策略。
NoClassDefFoundError 问题缘由1:缺乏jar包
首先最多见的缘由是classpath的配置问题。例子程序:
本例子程序尝试建立一个新的CallerClassA实例,而后执行他的一个方法,此方法引用了类ReferencingClassA,本例子演示了classpath问题致使的NoClassDefFoundError ,本例子还打印了当前的classloader chain的状况,以便进一步的分析。这个打印信息对你之后分析此类问题也颇有帮助的:
程序 工具
打印classloader工具类: ui
正常运行: google
异常重现: spa
发生了什么?当你在classpath中不包含guava的引用的时候,因为ReferencingClassA在运行期引用了此类,致使了classloader报告找不到此类,从而出现NoClassDefFoundError。
classloader分析
注意: .net
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中验证,确保编译和运行期都能找到此类。线程