我有一个使用 sbt 程序集插件打包为 uber-jar 的 Spark 作业。
这build.sbt
指定一个可运行的 main 作为生成的 uber-jar 的目标
mainClass in assembly := Some("com.foo.Bar")
正确创建程序集后,运行预期命令:
java -jar assembly.jar
结果是
错误:无法找到或加载主类 com.foo.Bar
使用替代方法,例如java -cp assembly.jar com.foo.Bar
给出相同的错误消息。
然后,我将 uber-jar 的内容提取到一个新目录中。我可以看到我的com/foo/
目录和Bar.class
文件。
从我尝试的提取目录的根目录:
java -cp . com.foo.Bar
我得到了正确的结果。
进一步尝试查找错误原因,我尝试:
java -verbose -jar assembly.jar
我可以看到正在加载 java 核心类,但没有看到任何打包的类正在加载。
这里可能出了什么问题?
经过广泛的调查(阅读:拔毛),事实证明这种行为是流氓的结果INDEX.LIST
来自降落在的扁平 jar 文件之一META-INF
生成的 uber-jar 的目录。
继JAR 文件规范 https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#JAR_Manifest, the INDEX.LIST
,如果存在,指示要加载 Jar 文件中的哪些包。
为了避免这种情况,我们更新了mergeStrategy
并制定规则以避免由此产生的任何污染META-INF
目录:
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
这解决了问题并恢复了我的理智。
Update:
经过一些额外的搜索,事实证明默认合并策略 https://github.com/sbt/sbt-assembly#merge-strategy妥善照顾INDEX.LIST
。当自定义合并策略包含处理以下情况时,此答案适用META-INF
pathSpec
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)