一次 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技能