我使用sbt程序集插件将一个spark工作打包为超级jar。
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核心类,但是我没有看到我的任何打包类被加载。
这里可能出现什么问题?
答案 0 :(得分:19)
经过广泛的调查(读取:拔出头发),事实证明这种行为是由于其中一个平展的jar文件落在INDEX.LIST
目录中的流氓META-INF
造成的。结果是超级罐子。
在JAR file spec之后,INDEX.LIST
(如果存在)指示要加载Jar文件中的哪些包。
为避免这种情况,我们使用规则更新了mergeStrategy
,以避免对生成的META-INF
目录造成任何污染:
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
这解决了这个问题并恢复了我的理智。
更新
经过一些额外搜索,结果default merge strategy正确照顾INDEX.LIST
。当自定义合并策略包含处理META-INF
pathSpec