怎麼解決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

類加載器的工做原理

相關文章
相關標籤/搜索