NoClassDefFoundError問題解決


  首先推薦一篇博客http://blog.csdn.net/jamesjxin/article/details/46606307

為我最初解決問題提供了入口。

  問題場景:

  由於我跑mapreduce任務需要按時間取數據,然而數據表是根據其他字段分區的,修改分區的話對現有的業務影響太大,於是改為跑任務之前先把表中的數據遷出,然后map遷出的hive表,來實現既定業務。

  問題如下:

  

$ ./UpdateUrlStatus.sh
當前時間零點:|1490976000000
17/04/01 13:29:32 INFO util.HiveClient: 加載參數完畢
17/04/01 13:29:33 INFO util.HiveClient: 加載驅動完畢=========org.apache.hive.jdbc.HiveDriver
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class hadooputils.util.HiveClient
    at mapreduce.avrocombine.UpdateUrlStatus.main(UpdateUrlStatus.java:189)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

程序中的問題代碼:

        
main:
    try{ if(HiveClient.createTable(parseTable, "exceptionparseall")){ HiveClient.insertDataToParse(parseTable, startTime, endTime); System.out.println("更新解析表數據完畢"); } if(HiveClient.createTable(extraceTable, "exceptionextractall")){ HiveClient.insertDataToExtract(extraceTable, startTime, endTime); System.out.println("更新抽取表數據完畢"); } } catch (SQLException e){ System.out.println(e.getMessage()); } catch (Exception e){ System.out.println(e.getMessage()); } finally { HiveClient.close(); }
public class HiveClient {
    private static String sql = "";  
    private static Statement stmt;
    private static Connection conn;
    private static ResultSet rs;
    private static final Logger log = Logger.getLogger(HiveClient.class);  
    
    static{
        if(conn==null||stmt==null){
            init();
        }
    }
    
    private static void init(){
        try {
            LoadProperty lp = new LoadProperty();
            Properties pro = lp.loadConfiguration("/hive.properties");
            String driverName = pro.getProperty("hive.driverName");
            String url = pro.getProperty("hive.url");
            String user = pro.getProperty("hive.user");
            String password = pro.getProperty("hive.password");
            log.info("加載參數完畢");
            Class.forName(driverName);
            log.info("加載驅動完畢=========" + driverName);
            conn = DriverManager.getConnection(url, user, password);
            log.info("建立連接完畢=========" + conn);
//            conn.setAutoCommit(false);
            stmt = conn.createStatement();
            log.info("Statement創建完畢");
        } catch (ClassNotFoundException e) {
            log.info("找不到驅動類");
        } catch (SQLException e) {
            log.info("初始化失敗");
        } catch (Exception e){
            log.info("初始化異常" + e.getMessage());
        }
    }
    
    public static void close(){
        try {
            if (rs != null) {  
                rs.close();  
                rs = null;  
            }  
            if (stmt != null) {  
                  stmt.close();  
                  stmt = null;  
              }  
            if (conn != null) {  
                conn.close();  
                conn = null;  
            }  
          
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
    }
...
}

  由博客中的介紹可以知道,NoClassDefFoundError也可能由於類的靜態初始化模塊錯誤導致,當你的類執行一些靜態初始化模塊操作,如果初始化模塊拋出異常,哪些依賴這個類的其他類會拋出NoClassDefFoundError的錯誤。如果你查看程序日志,會發現一些java.lang.ExceptionInInitializerError的錯誤日志,ExceptionInInitializerError的錯誤會導致java.lang.NoClassDefFoundError: Could not initialize class。

  於是在靜態塊中的init方法里加上日志,發現不是配置文件和驅動的問題,定位在獲取連接的語句上。然而main方法中並沒有把異常catch住,只是報了一個java.lang.NoClassDefFoundError的錯誤。

經過修改代碼,把靜態塊代碼注釋掉,init方法改為public,並在main方法中調用,然后就發現錯誤的日志改變了,如下:

$ ./UpdateUrlStatus.sh
當前時間零點:|1490976000000
17/04/01 14:36:45 INFO util.HiveClient: 加載參數完畢
17/04/01 14:36:45 INFO util.HiveClient: 加載驅動完畢=========org.apache.hive.jdbc.HiveDriver
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hive/service/cli/thrift/TCLIService$Iface
    at org.apache.hive.jdbc.HiveDriver.connect(HiveDriver.java:105)
    at java.sql.DriverManager.getConnection(DriverManager.java:571)
    at java.sql.DriverManager.getConnection(DriverManager.java:215)
    at hadooputils.util.HiveClient.init(HiveClient.java:37)
    at mapreduce.avrocombine.UpdateUrlStatus.main(UpdateUrlStatus.java:178)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.ClassNotFoundException: org.apache.hive.service.cli.thrift.TCLIService$Iface
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)

這樣就找到了問題真正的源頭,再把用於找問題的代碼修改回去,OK!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM