如何通过sbt assembly将本地构建的JAR包纳入Fat Jar构建
我明白你现在的困扰——已经摸透了基础的Fat Jar构建思路,但面对自己构建的本地依赖JAR(比如你测试用的magellan_2.11-1.0.6-SNAPSHOT.jar),不清楚该怎么把它纳入最终的组装包,连存放目录都拿不准。下面我结合Scala+Spark场景的常用构建工具(sbt)给你一步步讲清楚:
一、本地JAR的标准存放目录
首先,规范的做法是在你的Scala项目根目录下创建一个lib文件夹,把你自行构建的JAR包直接放到这个目录里。这是Java/Scala生态里存放非托管依赖(本地手动添加的JAR)的约定位置,主流构建工具(比如sbt、Maven)都会默认扫描这个目录下的JAR文件。
当然你也可以自定义目录,但lib目录最省心,不用额外配置路径,团队协作时也更容易统一。
二、用sbt-assembly打包Fat Jar的配置步骤
因为你用的是Scala+Spark,sbt是最常用的构建工具,而sbt-assembly是生成Fat Jar的主流插件,下面是具体配置:
1. 添加sbt-assembly插件
在项目根目录的project/plugins.sbt文件里添加插件依赖(可以用最新版本,这里举个稳定版例子):
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
2. 声明本地JAR依赖
sbt会自动识别lib目录下的JAR,但如果需要更明确的控制,或者你的JAR不在lib目录,也可以在build.sbt里显式声明:
// 如果JAR在lib目录下,这行可以省略,sbt会自动加载 unmanagedJars in Compile += file("lib/magellan_2.11-1.0.6-SNAPSHOT.jar") // 如果你的JAR在其他路径,比如桌面,就写绝对路径: // unmanagedJars in Compile += file("/Users/xxx/Desktop/magellan_2.11-1.0.6-SNAPSHOT.jar")
3. 配置assembly的合并策略(解决依赖冲突)
Spark项目打包Fat Jar时很容易遇到依赖冲突(比如Spark自带的库和你的依赖库重复),所以需要在build.sbt里设置合并策略:
assemblyMergeStrategy in assembly := { // 丢弃META-INF下的文件,避免签名冲突 case PathList("META-INF", xs @ _*) => MergeStrategy.discard // 其他文件优先保留第一个出现的版本,也可以根据需求调整 case x => MergeStrategy.first }
如果遇到特定类的冲突,可以单独针对该类设置策略,比如:
case PathList("com", "example", "ConflictClass.class") => MergeStrategy.last
4. 执行打包命令
在项目根目录下运行终端命令:
sbt assembly
打包完成后,Fat Jar会生成在target/scala-2.11/目录下(路径里的2.11对应你的Scala版本),文件名一般是{项目名}-assembly-{版本号}.jar。
三、验证与使用
打包完成后,你就不需要像之前用spark-shell那样用--jars指定依赖了,直接用spark-submit提交Fat Jar即可:
spark-submit --class com.yourpackage.YourMainClass target/scala-2.11/your-fat-jar-name.jar
关键注意点
- 确保本地JAR的Scala版本和你的项目完全一致(比如你的magellan JAR是2.11版本,项目的Scala也要用2.11),否则会出现兼容性错误。
- 如果你的本地JAR还有自己的依赖,这些依赖也会被
sbt-assembly自动打包进Fat Jar,除非你在配置里特意排除。
内容的提问来源于stack exchange,提问作者Codejoy

