ClassNotFoundException 即使 jar tvf 显示"缺失"类



当我在非本地环境中通过部署的jar(由maven shade插件构建)运行spark应用程序时,遇到了一个令人困惑的问题。

java.lang.RuntimeException: java.lang.ClassNotFoundException: org.postgresql.ds.PGSimpleDataSource
at com.zaxxer.hikari.util.UtilityElf.createInstance(UtilityElf.java:96)
at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:314)
at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:108)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:105)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:72)
at mypackage.SansORMProvider.get(SansORMProvider.java:42)
at mypackage.MySansORMProvider.get(MySansORMProvider.scala:15)
at mypackage.MyApp$.main(MyApp.scala:63)
at mypackage.MyApp.main(MyApp.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.spark.deploy.yarn.ApplicationMaster$$anon$2.run(ApplicationMaster.scala:680)
Caused by: java.lang.ClassNotFoundException: org.postgresql.ds.PGSimpleDataSource
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.zaxxer.hikari.util.UtilityElf.createInstance(UtilityElf.java:83)
... 13 more

这之所以令人困惑,是因为以下内容在我的pom.xml中:

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>compile</scope>
</dependency>

shade插件没有引用这个postgres依赖项的配置,也没有任何匹配它的模式

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
<configuration>
<artifactSet>
<excludes combine.children="append">
<exclude>org.apache.spark:*:*</exclude>
<exclude>org.apache.hadoop:*:*</exclude>
<exclude>org.slf4j:*</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>${project.groupId}.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>io.netty</pattern>
<shadedPattern>${project.groupId}.io.netty</shadedPattern>
</relocation>
<relocation>
<pattern>okhttp3</pattern>
<shadedPattern>${project.groupId}.okhttp3</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>${project.groupId}.fasterxml.jackson</shadedPattern>
</relocation>
]
</relocations>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</execution>
</executions>
</plugin>

Spark依赖关系(根据要求):

<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.4.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-mllib_2.11</artifactId>
<version>2.4.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.4.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-tags_2.11</artifactId>
<version>2.4.3</version>
<scope>provided</scope>
</dependency>

在构建jar的maven命令的输出中,我可以看到[INFO] Including org.postgresql:postgresql:jar:42.2.1 in the shaded jar.

当我运行jar tvf myShadedJar.jar | grep postgres时,我可以看到缺少的类。

一件可能相关的奇怪事情是,当我用jar xf解压缩jar时,没有org/postgresql文件夹。然而,当我unzip罐子时,它就在那里。

可能是什么问题?我该如何确认?爆炸后的jar是否缺少org/postgresql文件夹?

我在将我们的spark应用程序从AWS EMR 5.24.1迁移到5.33.0时遇到了完全相同的问题。经过几周的定期尝试,我最终意识到在执行过程中没有使用我们uber jar中的HikariCP包。当我将HikariCP从胖罐子中排除时,这一点变得很明显,错误没有改变,尽管我预计它会抱怨没有找到HikariCP
事实证明,EMR 5.33.0在多个lib文件夹中有HikariCP-java7-2.4.12.jar,并且在运行时使用此包(而不是uber jar中的包)。我只是从主节点和核心节点上删除了这个包的所有场合,这就解决了问题

我希望这能帮助那些对类似问题感到沮丧的人。

编辑:根据OP的新信息,这不太可能是答案

看起来您遇到了这个问题:https://github.com/jeremylong/DependencyCheck/issues/2324

不幸的是,阴影罐子代表了一个挑战。在以下情况下从属库是";带阴影的";中包含pom.xmlMETA-INF目录(即由maven构建或使用maven插件对于gradle)-然后我们可以提取信息并检测依赖性。然而,在commons文件上传的情况下,它们不会在META-INF中有一个pom.xml(不完全确定是什么构建系统他们使用)。因此,依赖性检查将无法识别依赖性。不幸的是,阴影或uber jar(实际上,对uber jar来说更糟糕)。甚至有几个商业产品很难做到这一点。

您可以将文件从项目中显式复制到着色的jar中(例如,将jar文件的副本放在src/main/resources目录中)。

或者,您可以在您的maven项目中创建一个子模块,其中包含这个jar(以及其他可能遇到相同问题的jar)。然后添加子模块作为依赖项,并让shade插件包含它

最新更新