零、背景:
今天新开发一个组件,spark写入Pegasus。因为打包问题频繁报错。复盘一下这两天走的弯路。
首先说正确的路径:直接找官方,获取最合适的依赖包,参照样例代码,写业务逻辑,避免版本问题。
(从找到这条正确路径到真正开发完,只用了一个小时的时间。)
之前其他时间都用在jar包冲突的解决上了。
恰逢公司spark由2.x升级到3.x,而我引用的Pegasus-client是使用2.x的,所以Pegasus组件适用的组件版本就太低了。一直报java.lang.NoClassDefFoundError: scala/math/PartialOrdering$class
错误。
这里有一位博主写了一些类似的坑
一、我碰到的问题:
(一)java.lang.NoClassDefFoundError: scala/math/PartialOrdering$class 错误。
首先,要能识别这是jar包冲突的问题,碰到NoClassDefFoundError或者NoSuchMethodError,基本就是jar包冲突的问题了。
NoClassDefFound并不是真的在运行中找不到这个类,而是加载不到自己需要的这个类, 这次是运行环境里的Scala版本是适合spark3.1的2.12版本,而Pegasus包选错版本了,选成了适合spark2.x的版本,里面自带的spark版本和Scala版本都是适合spark2.x的。所以在类加载过程中,由于运行环境是spark3.1,相应的Scala也是2.12,所以加载到也Scala2.12,而该Pegasus需要的Scala版本是2.11,用的是2.11里的方法,可能这个方法刚好在2.12里做了修改,所以在调用Pegasus的方法时,才会报找不到Scala的类或方法的错误。
jar包冲突是我们工程开发中常见的问题,如何排查,可以用以下的方法解决:
1.定位冲突的jar包位置:
方法一:用maven自带的插件工具maven helper定位
安装方式:(IDEA) file-setting-plugins ,搜索 maven helper,安装成功后,在pom页下面就可以看到 dependency analyzer,切换到这里后,就可以看到可视化的依赖关系。第三个是依赖树 all dependency As tree 。
看冲突的话可以看第一个conflicts.搜索报冲突的包,比如Scala,然后右键,exclude,就可以将该包排除掉(这里只是举个例子,我的工程已经跑通了),在这里排除掉之后,回到TXT格式后就会发现多了一个exclude。
方法二、利用IDEA快捷键Shift+Ctrl+Alt+N来查找
这里由于是查找的Scala,依赖的比较多,一般情况下的冲突不会这么多,可能就两个,排除掉一个就好了。
方法三、利用maven树,点击maven自带的show dependency按钮,就会生成maven依赖树。
ctrl +f就能找到冲突的包。
2.找到冲突之后,该如何解决冲突呢
方法一、排除掉冲突的版本,只保留一个最合适的版本:
如何知道该排除哪个版本呢:
1)根据经验
比如本次,知道spark3和spark2对应需要的Scala版本,所以很自然地就知道排除掉Scala2.11相关的版本。
2)去官方仓库看
https://mvnrepository.com/artifact/org.apache.spark/spark-core
这里就能看到spark版本对应的Scala版本。
方法二、用maven-shade打包,也就是说将这些冲突的版本打包时命名为后缀为shaded的包里,运行时不会调用,全用线上的版本。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<artifactSet>
<excludes>
<exclude>org.apache.spark:*</exclude>
<exclude>org.scala-lang:*</exclude>
<exclusion>org.apache.hadoop:*</exclusion>
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.apache.thrift</pattern>
<shadedPattern>org.shaded.thrift</shadedPattern>
<excludes>
<exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
<exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
</excludes>
</relocation>
<relocation>
<pattern>io.netty.handler.ssl</pattern>
<shadedPattern>shade.io.netty.handler.ssl</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
以上,NoClassDefFoundError的错误得到了解决。