查看原文
其他

一次 Maven 事故

ImportNew 2021-12-02

(点击上方公众号,可快速关注)


来源: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技能

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存