You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于sbt-assembly打包Spark依赖行为异常的咨询

为什么两个sbt-assembly配置生成的Jar大小差异巨大?

你的问题核心在于两个配置的合并策略逻辑差异,以及第一个配置中存在的语法/顺序错误,导致Spark的provided依赖被意外打包进Jar:

1. 第二个配置为什么Jar很小?

第二个配置的策略简洁且没有破坏默认逻辑:

assemblyMergeStrategy in assembly := {
  case "src/test/resources/library.properties" => MergeStrategy.discard
  case PathList("META-INF", xs@_*) => MergeStrategy.discard
  case x => MergeStrategy.first
}
  • 它直接丢弃了所有META-INF下的文件(这部分多是依赖元数据,不影响业务代码运行),剩余文件采用MergeStrategy.first规则避免冲突。
  • 更关键的是,这个配置没有干扰sbt-assembly的默认依赖排除逻辑:你标记为provided的Spark依赖会被正确排除,最终Jar仅包含你的业务代码和必要的非provided依赖,所以体积只有10MB。

2. 第一个配置为什么Jar很大(包含Spark)?

第一个配置存在两个关键问题:

(1)模式匹配顺序错误,默认策略完全失效

你的第一个配置最后两行是:

case x => MergeStrategy.first
case x => val oldStrategy = (assemblyMergeStrategy in assembly).value oldStrategy(x)

Scala模式匹配是从上到下顺序匹配的,第一个case x会捕获所有未被前面规则覆盖的文件,导致后面试图回退到默认策略的代码根本不会执行。

(2)语法错误导致配置异常

第二行的写法存在语法问题:val oldStrategy = (assemblyMergeStrategy in assembly).value oldStrategy(x) 缺少必要的分号或调用语法,正确的回退写法应该是case x => (assemblyMergeStrategy in assembly).value(x)。
这个语法错误可能导致sbt加载配置时出现异常,进而意外破坏了默认的依赖排除逻辑——Spark的provided依赖没有被正确识别,最终被打包进Jar,直接让体积暴涨到109MB。

(3)过度宽泛的合并规则

第一个配置对org.apache、com.google等顶级包采用MergeStrategy.last规则,意味着这些包下的冲突文件会保留最后找到的版本。如果Spark依赖的文件被意外收集到,这个规则会让它们被合并进Jar,进一步增大了体积。

3. 修复第一个配置的建议

如果你想保留特定的合并规则,同时正确排除Spark的provided依赖,可以修正配置如下:

assemblyMergeStrategy in assembly := {
  case PathList("org", "aopalliance", xs@_*) => MergeStrategy.last
  case PathList("javax", "inject", xs@_*) => MergeStrategy.last
  case PathList("javax", "servlet", xs@_*) => MergeStrategy.last
  case PathList("javax", "activation", xs@_*) => MergeStrategy.last
  case PathList("org", "apache", xs@_*) => MergeStrategy.last
  case PathList("com", "google", xs@_*) => MergeStrategy.last
  case PathList("com", "esotericsoftware", xs@_*) => MergeStrategy.last
  case PathList("com", "codahale", xs@_*) => MergeStrategy.last
  case PathList("com", "yammer", xs@_*) => MergeStrategy.last
  case "about.html" => MergeStrategy.rename
  case "META-INF/ECLIPSEF.RSA" => MergeStrategy.last
  case "META-INF/MANIFEST.MF" => MergeStrategy.discard
  case "META-INF/mailcap" => MergeStrategy.last
  case "META-INF/mimetypes.default" => MergeStrategy.last
  case "plugin.properties" => MergeStrategy.last
  case "log4j.properties" => MergeStrategy.last
  case "git.properties" => MergeStrategy.discard
  // 自定义规则在前,最后回退到默认策略
  case x => (assemblyMergeStrategy in assembly).value(x)
}
  • 移除了错误的case x => MergeStrategy.first,将回退默认策略的代码放在最后
  • 修正了语法错误,确保默认的依赖排除逻辑正常工作
  • 这样既保留了你需要的特定合并规则,又能让Spark的provided依赖被正确排除,生成的Jar体积会和第二个配置接近。

内容的提问来源于stack exchange,提问作者3nomis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:21:57