1 背景:
筆者在自己編寫flink代碼并進行本地測試時遇到,報錯如下:這個問題明顯是說在編譯時JVM加載不到類或者找不到類導緻的,于是報了
java.lang.ClassNotFoundException
,而且在運作時JVM加載不到類或者找不到類直接報錯
java.lang.NoClassDefFoundError
,
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/flink/api/scala/typeutils/CaseClassTypeInfo
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at org.myself.function.FunctionTest.main(FunctionTest.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.flink.api.scala.typeutils.CaseClassTypeInfo
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 13 more
2 報錯分析
在上邊我們提到
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError
報錯都是因為JVM加載不到類或者找不到類發生異常或者報錯,然而兩者存在本質差別那就是
java.lang.ClassNotFoundException
是在
編譯時
報錯,
java.lang.NoClassDefFoundError
是在
運作時
報錯。那麼這裡我們這個報錯是怎麼回事呢?
我們先來看
java.lang.NoClassDefFoundError
報錯,看到這個我們和容易想到這和java的JVM類加載機制有關,那麼我們就需要了解下JVM的類加載機制雙親委派機制,什麼是雙親委派機制呢?說的粗糙點就是java為我們提供了很多的類庫,而不同的類庫之間存在血緣關系。當某個類加載器需要加載某個.class檔案時,它首先把這個任務委托給他的上級類加載器,遞歸這個操作,如果上級的類加載器沒有加載,自己才會去加載這個類。
類加載器又分為:
-
BootstrapClassLoader
(啟動類加載器)
c++編寫,加載java核心庫 java.*,構造
。由于引導類加載器涉及到虛拟機本地實作細節,開發者無法直接擷取到啟動類加載器的引用,是以不允許直接通過引用進行操作ExtClassLoader和AppClassLoader
-
ExtClassLoader
(标準擴充類加載器)
java編寫,加載擴充庫,如classpath中的jre ,javax.*或者
java.ext.dir 指定位置中的類,開發者可以直接使用标準擴充類加載器。
-
AppClassLoader
(系統類加載器)
java編寫,加載程式所在的目錄,如user.dir所在的位置的class
-
CustomClassLoader
(使用者自定義類加載器)
java編寫,使用者自定義的類加載器,可加載指定路徑的class檔案
詳細的加載過程如圖所示:
由上面的過程我們可以發現在程式運作時,他通路了所有的類庫之後才會發生這個報錯
的報錯,這說明我們項目的maven文添加或者maven庫出現問題或者通路不到了。那麼順着這個思路我們一路排查先看項目是否配置了相關依賴我們發現,依賴的配置的相當齊全, 那麼我們看maven庫是否有問題,我們在本地随便找個項目發現maven庫正常,那麼說明本次的報錯顯然是maven依賴無法通路造成的,為啥會這樣呢?細心的同學已經發現原來我在項目中添加了NoClassDefFoundError
這個操作是為了什麼呢?這個操作其實是為了在打包到叢集時我們不攜帶本地的flink環境,因為叢集上環境已經準備好這個時候問題顯然是已經找到。那麼怎麼解決呢?<scope>provided</scope>
3 問題解決
其實很簡單,筆者用的是IDEA 如果大家用的其他的程式設計工具可以自行百度下解決辦法,這裡就說下我是怎麼搞得,熟悉IDEA工具的同學會發現在IDEA的工具欄有一個運作配置。我們在運作前點開
我們發現在
Configuration>>Use classpath of moudle中有一個include dependencies provided scope
的選框,這個時候我們把勾選上就完了。
再來運作我們發現完美解決了問題:
4 總結
本次報錯主要由于操作着急引起,之是以寫在這裡隻為警示自己和為大家解決類似問題提供思路。當然上面分析我們借助對
java.lang.NoClassDefFoundError
報錯的分析就解決了問題,在這了筆者也總結下其他引起
java.lang.NoClassDefFoundError
和
java.lang.ClassNotFoundException
的原因及情況,希望能幫到大家如下:
-
可能出現的情況NoClassDefFoundError
- 一種情況就是因為靜态變量加載不到原因
- 工程裡沒有将jar添加到classpath,maven項目的,需要根據項目情況排查
-
java開發中經常遇到java.lang.ClassNotfoundException異常,ClassNotfoundException異常一般就是編譯時找不到類,Console台就會輸出異常資訊。一般情況下,我們都會ClassNotfoundException
一下工程,讓項目重新編譯一遍。rebuild或者clean