【问题标题】:ClassNotFoundException even though jar tvf shows the 'missing' classClassNotFoundException 即使 jar tvf 显示“缺失”类
【发布时间】:2021-10-29 07:18:06
【问题描述】:

当我在非本地环境中通过已部署的 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 文件夹吗?

【问题讨论】:

  • 你是否使用 Spring Boot 或任何其他框架进行自定义类加载?
  • 您确定要写java tvf myShadedJar.jar | grep postgres 而不是tar tvf myShadedJar.jar | grep postgres
  • @dan1st 项目中的其他模块使用 google guice(不确定是否会加载自定义类),但不是这个。
  • 请看 maven-shade-plugin 的完整 pom 配置。 BTW @GeroldBroser 我相信异常是由 Apache Spark 包装的。见这里:databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
  • Your last update 导致“当我用jar xf 解压缩jar 时,没有org/postgresql 文件夹。然而,当我unzip jar 时它就在那里。 “改变事物。如果您提供完整的 POM(可能包含匿名的敏感信息),我可以在这里创建一个项目,看看我是否可以确认此行为并可能找到原因。我也需要你使用的 JDK 和 Maven 版本。

标签: java maven apache-spark maven-shade-plugin


【解决方案1】:

在将 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 中的那个)。 我只是从主节点和核心节点中删除了这个包的所有场合,这就解决了问题。

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

【讨论】:

    【解决方案2】:

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

    您似乎遇到了这个问题:https://github.com/jeremylong/DependencyCheck/issues/2324

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

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

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

    【讨论】:

    • 您在其中一个 cmets 中链接到问题的 Spark page 使用 &lt;scope&gt;provided 声明了所有 Spark 依赖项。 provided 工件中很可能没有 pom.xml。我建议在构建之前使用install:install-filedeploy:deploy-file,即创建Fat JAR。
    • 续:1) 这是最干净的 Maven 方式。 2)那时不需要显式复制。 3) 这样就不需要创建额外的项目了。
    • 抱歉,您能解释一下这与我的问题有何关系吗?您的报价来自一个名为 DependencyCheck 的项目。您是说 spark 使用相同的机制并且它看不到它吗?
    • 我之前试过子模块的方法,还是不行。
    • @GeroldBroser 我将依赖项包含在编译范围内。它不是火花依赖。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 2011-09-30
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多