在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中驗證,確保編譯和運行期都能找到此類。線程