淺談NoClassDefFoundError

最近因?yàn)轫?xiàng)目的原因薛夜,發(fā)現(xiàn)一個(gè)運(yùn)行時(shí)錯(cuò)誤:NoClassDefFoundError歪脏,對(duì)于這個(gè)常見(jiàn)的java Error進(jìn)行一下總結(jié)技潘。同時(shí)區(qū)分一下NoClassDefFoundError與ClassNotFoundException。

ClassNotFoundException

下面是一個(gè)ClassNotFoundException出現(xiàn)的場(chǎng)景分飞,當(dāng)使用JDBC去連接數(shù)據(jù)庫(kù)的時(shí)候悴务,一般會(huì)使用Class.forName()的方式去加載JDBC的驅(qū)動(dòng),如果沒(méi)有將驅(qū)動(dòng)放到應(yīng)用的classpath下譬猫,那么會(huì)導(dǎo)致運(yùn)行時(shí)找不到類讯檐,所以運(yùn)行Class.forName()會(huì)拋出ClassNotFoundException:

public class MainClass {
    public static void main(String[] args) {
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Log

java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at com.ebay.app.SampleResource.main(SampleResource.java:43)

NoClassDefFoundError

NoClassDefFoundError是一個(gè)運(yùn)行時(shí)異常,造成這個(gè)異常的原因染服,是在運(yùn)行過(guò)程中别洪,JVM無(wú)法找到運(yùn)行時(shí)需要的class文件。

為什么在編譯時(shí)能夠通過(guò)柳刮,但是運(yùn)行時(shí)卻無(wú)法找到對(duì)應(yīng)的class類挖垛。下面舉一個(gè)例子痒钝。
有三個(gè)類,DependencyA(A)晕换,DependencyB(B)午乓,DependencyC(C)站宗。這三個(gè)類是不同項(xiàng)目下的闸准。

其中依賴關(guān)系:

  • A依賴B,并使用B中的打印方法:


  • B中依賴C梢灭,并使用了C中的方法:


pom.xml 如下:

<dependencies>
      <dependency>
           <groupId>com.test</groupId>
           <artifactId>C</artifactId>
           <scope>provided</scope>
      </dependency>
</dependencies>
  • C只是進(jìn)行一個(gè)簡(jiǎn)單的輸出:


NoClassDefFoundError

當(dāng)執(zhí)行A中的main方法時(shí)夷家,可以看到,正常打印了A中的語(yǔ)句和B中的語(yǔ)句敏释,但是在繼續(xù)運(yùn)行C的方法的時(shí)候库快,出現(xiàn)異常java.lang.NoClassDefFoundError: com/demo/c/DependencyC

  • Log


  • Pom
    由于demo中的代碼使用maven進(jìn)行依賴管理,需要考慮依賴問(wèn)題钥顽。當(dāng)查看pom文件配置后發(fā)現(xiàn)义屏,程序A中只引入了B所在的jar包,但是對(duì)于B中需要的C類的jar包沒(méi)有做依賴聲明蜂大。
<dependencies>
      <dependency>
           <groupId>com.test</groupId>
           <artifactId>B</artifactId>
      </dependency>
</dependencies>
  • 分析
    A的做法是標(biāo)準(zhǔn)的Maven的做法闽铐,但是由于B對(duì)C的依賴是provided。而對(duì)于scope=provided的情況奶浦,maven 不會(huì)管理C兄墅,因此在class path 就沒(méi)有C的jar。最常見(jiàn)的這類artifact是servlet-api.jar澳叉。
    當(dāng)JVM在進(jìn)行類加載的過(guò)程中隙咸,A依賴B,加載B的時(shí)候成洗,從當(dāng)前的依賴的Jar中找到對(duì)應(yīng)的class文件五督,B中打印語(yǔ)句可以正常執(zhí)行。當(dāng)B依賴C瓶殃,JVM開(kāi)始加載C的過(guò)程中發(fā)現(xiàn)概荷,無(wú)法在當(dāng)前class path中找到對(duì)應(yīng)的class文件,所以在這種情況下碌燕,就會(huì)報(bào)出NoClassDefFoundError误证。

其它出現(xiàn)NoClassDefFoundError的形式

其實(shí)還有更簡(jiǎn)單的形式,例如編譯通過(guò)后修壕,手動(dòng)刪除引用的某個(gè)class文件愈捅;修改引用的jar包名稱。歸根結(jié)底慈鸠,NoClassDefFoundError出現(xiàn)的原因都是因?yàn)轭惣虞d過(guò)程中沒(méi)有辦法找到對(duì)應(yīng)的class文件蓝谨。
在源碼中也明確寫道,當(dāng)JVM或類加載器嘗試加載一個(gè)類時(shí),這個(gè)類對(duì)應(yīng)的class文件沒(méi)有找到時(shí)譬巫,JVM會(huì)報(bào)出當(dāng)前的錯(cuò)誤咖楣。


/**
 * Thrown if the Java Virtual Machine or a <code>ClassLoader</code> 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 <code>new</code> expression)
 * and no definition of the class could be found.
 * <p>
 * The searched-for class definition existed when the currently
 * executing class was compiled, but the definition can no longer be
 * found.
 *
 * @author  unascribed
 * @since   JDK1.0
 */
public
class NoClassDefFoundError extends LinkageError {
    private static final long serialVersionUID = 9095859863287012458L;

    /**
     * Constructs a <code>NoClassDefFoundError</code> with no detail message.
     */
    public NoClassDefFoundError() {
        super();
    }

    /**
     * Constructs a <code>NoClassDefFoundError</code> with the specified
     * detail message.
     *
     * @param   s   the detail message.
     */
    public NoClassDefFoundError(String s) {
        super(s);
    }
}

解決方案

以demo中演示的代碼為例,只需要在A所在的Project中引入C所在的依賴芦昔,即可解決當(dāng)前問(wèn)題:


NoClassDefFoundError與ClassNotFoundException

如果JVM或者ClassLoader在加載類時(shí)找不到對(duì)應(yīng)的類诱贿,就會(huì)引發(fā)NoClassDefFoundError和ClassNotFoundException。由于不同的ClassLoader會(huì)從不同的地方加載類咕缎,有時(shí)是錯(cuò)誤的CLASSPATH引發(fā)這類錯(cuò)誤珠十,有時(shí)是某個(gè)庫(kù)的jar包缺失引發(fā)這類錯(cuò)誤。NoClassDefFoundError和ClassNotFoundException之間存在一些細(xì)微的不同點(diǎn)凭豪。

NoClassDefFoundError

  • 表示該類在編譯階段還可以找到焙蹭,但是在運(yùn)行Java應(yīng)用的時(shí)候找不到了,有時(shí)靜態(tài)塊的初始化過(guò)程會(huì)導(dǎo)致NoClassDefFoundError嫂伞。
  • NoClassDefFoundError是Error孔厉,是unchecked,因此也不需要使用try-catch或者finally語(yǔ)句塊包圍帖努。
  • NoClassDefFoundError 是鏈接錯(cuò)誤撰豺,發(fā)生在鏈接階段,當(dāng)解析引用的時(shí)候找不到對(duì)應(yīng)的類然磷,就會(huì)拋出java.lang.NoClassDefFoundError郑趁;ClassNotFoundException是異常,發(fā)生在運(yùn)行階段姿搜。

常見(jiàn)Case

如果開(kāi)發(fā)中遇到NoClassDefFoundError寡润,那么最有可能的原因

  • jar 包不存在
  • 存在多個(gè)類加載器和多個(gè)目標(biāo)類,即我們常說(shuō)的Jar包沖突舅柜。比如說(shuō)上文的B 梭纹,如果有兩個(gè)版本的B存在于依賴中 中, B1是compile scope 致份, B2 是provided scope变抽,如果maven 解析到B1,就不會(huì)有NoClassDefFoundError的問(wèn)題氮块,但是解析到B2绍载,就有NoClassDefFoundError的問(wèn)題。這種情況迷惑性比較大滔蝉,第一次build 是可以的击儡,同樣的code 第二次build 就不可以了。非常難以定位蝠引。解決這種問(wèn)題阳谍,通常需要用mvn dependency tree 來(lái)查看到底引用了哪些同名的Artifact蛀柴,進(jìn)而exclude 錯(cuò)誤的artifacts。

ClassNotFoundException

  • 和編譯期沒(méi)什么關(guān)系矫夯,當(dāng)你在代碼中顯式加載類(使用Class.forName())時(shí)沒(méi)有找到對(duì)應(yīng)的類鸽疾,則會(huì)拋出java.lang.ClassNotFoundException。例如加載SQL驅(qū)動(dòng)時(shí)训貌,對(duì)應(yīng)的類加載器找不到驅(qū)動(dòng)類制肮。
  • ClassNotFoundException是受檢異常(checked Exception),因此需要使用try-catch語(yǔ)句塊或者try-finally語(yǔ)句塊包圍旺订,否則會(huì)導(dǎo)致編譯錯(cuò)誤

常見(jiàn)Case

調(diào)用Class.forName()弄企、ClassLoader.findSystemClass()和ClassLoader.loadClass()等方法時(shí)可能會(huì)引起java.lang.ClassNotFoundException超燃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載区拳,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末意乓,一起剝皮案震驚了整個(gè)濱河市樱调,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌届良,老刑警劉巖笆凌,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異士葫,居然都是意外死亡乞而,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門慢显,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)爪模,“玉大人,你說(shuō)我怎么就攤上這事荚藻∥莨啵” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵应狱,是天一觀的道長(zhǎng)共郭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)疾呻,這世上最難降的妖魔是什么除嘹? 我笑而不...
    開(kāi)封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮岸蜗,結(jié)果婚禮上尉咕,老公的妹妹穿的比我還像新娘。我一直安慰自己散吵,他們只是感情好龙考,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蟆肆。 她就那樣靜靜地躺著,像睡著了一般晦款。 火紅的嫁衣襯著肌膚如雪炎功。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天缓溅,我揣著相機(jī)與錄音蛇损,去河邊找鬼。 笑死坛怪,一個(gè)胖子當(dāng)著我的面吹牛淤齐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袜匿,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼更啄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了居灯?” 一聲冷哼從身側(cè)響起祭务,我...
    開(kāi)封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怪嫌,沒(méi)想到半個(gè)月后义锥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岩灭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年拌倍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片噪径。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柱恤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出熄云,到底是詐尸還是另有隱情膨更,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布缴允,位于F島的核電站荚守,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏练般。R本人自食惡果不足惜矗漾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薄料。 院中可真熱鬧敞贡,春花似錦、人聲如沸摄职。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蛔垢,卻和暖如春击孩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹏漆。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工巩梢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艺玲。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓括蝠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親饭聚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忌警,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容