歡迎光臨
每天分享高質量文章

一次 Maven 事故

(點選上方公眾號,可快速關註)


來源:whatbeg,

whatbeg.com/2017/12/24/mavenaccident.html

改動mllib中的org.apache.spark.ml.tree.impl.DTStatsAggregator原始碼,加了一個原來沒有的allStats(): Array[Double] = ..的方法,然後打成MLlib包,替換maven庫中的mllib包。

報IllegalAccessError:

Caused by: java.lang.IllegalAccessError: tried to access method org.apache.spark.ml.tree.impl.DTStatsAggregator.allStats()[D from class org.apache.spark.ml.tree.impl.RandomForestImpl$

private[ml] val allStatSize

val allStats = new Array[Double](allStatSize)

應該要能訪問到

是不是用的不是我的jar,或者用的不是我的jar中的class?

執行jar包時設定

–conf “spark.driver.extraJavaOptions=-XX:+TraceClassLoading -XX:+TraceClassUnloading

監測類的載入情況,果然發現有一條

[Loaded xxx from file:/home/huqiu/programs/spark/jars/spark-mllib_2.11-2.1.0.jar

這說明程式不從我打好的jar包中載入class,而從spark安裝目錄中的jars目錄中讀取了。

為什麼從spark本地讀而不從打好的jar包中讀?

為了先解決問題,我把mllib包複製到SPARK_HOME的jars目錄中,這下總能讀到我的jar了吧。

但是又出現一個問題:

java.lang.NoClassDefFoundError: Could not initialize class org.apache.spark.ml.core.JNAScala$

 

Caused by: java.lang.ClassNotFoundException: com.sun.jna.Native

原來是沒找到jna的Native class,一看,確實沒有打入mllib包中,那是什麼原因呢?難道是誰把它exclude掉了?

重新編譯一下,發現這麼一條:

[INFO] Excluding net.java.dev.jna:jna:jar:4.2.2 from the shared jar.

說白了就是排除了net.java.dev.jna:jna:jar,所以寫的程式碼中用到Native的都會找不到類。

後來發現是spark-parent排除的,且刪掉spark-parent的exclude的陳述句也沒用,根本原因在於mllib的打包方式不會把其依賴打入mllib的jar包中。

解決的方法就是將此依賴打入mllib中,但是這樣就會變成mllib-jar-with-dependencies,肯定不是我們想要的結果。

這就涉及到了程式碼設計的層面了,一般情況下,不建議直接修改Mllib原始碼,更不要說在Mllib原始碼中還加入外部包了,這樣太緊耦合了,比較建議的方法是自己建立一個project,建立於spark mllib同樣的包路徑即可,然後修改需要修改的檔案,但缺點是改動檔案需要改名字,不然系統會讀取底層Mllib的同名檔案而不會讀取你專案中的。但是這樣確是松耦合的。

目前還沒有找到好的方法,最小程度上改動程式碼,增加或刪除一些東西。

看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

贊(0)

分享創造快樂