【问题标题】:How to build an Uber JAR (Fat JAR) using SBT within IntelliJ IDEA?如何在 IntelliJ IDEA 中使用 SBT 构建 Uber JAR (Fat JAR)?
【发布时间】:2015-04-12 02:50:06
【问题描述】:

我正在使用 SBT(在 IntelliJ IDEA 中)构建一个简单的 Scala 项目。

我想知道构建 Uber JAR 文件(又名 Fat JAR、Super JAR)的最简单方法是什么。

我目前正在使用 SBT,但是当我将 JAR 文件提交到 Apache Spark 时,我收到以下错误:

线程“主”java.lang.SecurityException 中的异常:无效 Manifest 主要属性的签名文件摘要

或者编译时出现这个错误:

java.lang.RuntimeException: deduplicate: 发现不同的文件内容 在以下:
PATH\DEPENDENCY.jar:META-INF/DEPENDENCIES
PATH\DEPENDENCY.jar:META-INF/MANIFEST.MF

looks like 这是因为我的一些依赖项包含签名文件 (META-INF),需要在最终的 Uber JAR 文件中删除。

我尝试像这样使用sbt-assembly 插件:

/project/assembly.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

/project/plugins.sbt

logLevel := Level.Warn

/build.sbt

lazy val commonSettings = Seq(
  name := "Spark-Test"
  version := "1.0"
  scalaVersion := "2.11.4"
)

lazy val app = (project in file("app")).
  settings(commonSettings: _*).
  settings(
    libraryDependencies ++= Seq(
      "org.apache.spark" %% "spark-core" % "1.2.0",
      "org.apache.spark" %% "spark-streaming" % "1.2.0",
      "org.apache.spark" % "spark-streaming-twitter_2.10" % "1.2.0"
    )
  )

当我在 IntelliJ IDEA 中单击“Build Artifact...”时,我得到一个 JAR 文件。但我最终得到了同样的错误......

我是 SBT 的新手,对 IntelliJ IDE 的试验并不多。

谢谢。

【问题讨论】:

标签: scala intellij-idea sbt meta-inf uberjar


【解决方案1】:

最后我完全跳过了使用 IntelliJ IDEA 以避免在我的全局理解中产生噪音 :)

我开始阅读official SBT tutorial

我使用以下文件结构创建了我的项目:

my-project/project/assembly.sbt
my-project/src/main/scala/myPackage/MyMainObject.scala
my-project/build.sbt

在我的 assembly.sbt 文件中添加了 sbt-assembly plugin。允许我构建一个胖 JAR:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

我最小的 build.sbt 看起来像:

lazy val root = (project in file(".")).
  settings(
    name := "my-project",
    version := "1.0",
    scalaVersion := "2.11.4",
    mainClass in Compile := Some("myPackage.MyMainObject")        
  )

val sparkVersion = "1.2.0"

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-core" % sparkVersion % "provided",
  "org.apache.spark" %% "spark-streaming" % sparkVersion % "provided",
  "org.apache.spark" %% "spark-streaming-twitter" % sparkVersion
)

// META-INF discarding
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
   {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case x => MergeStrategy.first
   }
}

注意% "provided" 表示不在最终的胖 JAR 中包含依赖项(这些库已经包含在我的工作人员中)

注意:META-INF 丢弃inspired by this answser

注意%%%的含义

现在我可以通过在我的 /my-project 根文件夹中运行以下命令,使用 SBT (how to install it) 构建我的胖 JAR:

sbt assembly

我的胖 JAR 现在位于新生成的 /target 文件夹中:

/my-project/target/scala-2.11/my-project-assembly-1.0.jar

希望对其他人有所帮助。


对于那些想要在 IntelliJ IDE 中嵌入 SBT 的用户:How to run sbt-assembly tasks from within IntelliJ IDEA?

【讨论】:

【解决方案2】:

将以下行添加到您的项目/plugins.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

将以下内容添加到您的 build.sbt

mainClass in assembly := some("package.MainClass")
assemblyJarName := "desired_jar_name_after_assembly.jar"

val meta = """META.INF(.)*""".r
assemblyMergeStrategy in assembly := {
  case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
  case n if n.startsWith("reference.conf") => MergeStrategy.concat
  case n if n.endsWith(".conf") => MergeStrategy.concat
  case meta(_) => MergeStrategy.discard
  case x => MergeStrategy.first
}

Assembly 合并策略用于解决创建 fat jar 时发生的冲突。

【讨论】:

  • 您可以通过在控制台中运行“sbt assembly”来创建fat Jar
  • 对于 scala 版本 2.11.8(SBT 版本:0.13.12)将 addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0") 放入 project/assembly.sbt
【解决方案3】:

在 IntelliJ Idea 中构建 Uber JAR/Fat JAR 的 3 步流程:

Uber JAR/Fat JAR:包含所有外部库依赖项的 JAR 文件。

  1. 在 IntelliJ Idea 中添加 SBT Assembly 插件

    转到 ProjectName/project/target/plugins.sbt 文件并添加这一行 addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. 在 build.sbt 中添加 Merge、Discard 和 Do Not Add 策略

    转到 ProjectName/build.sbt 文件并添加 Uber JAR 打包策略

    合并策略:如果两个包中存在关于库版本的冲突,那么将哪个包打包到 Uber JAR 中。
    丢弃策略:删除一些您不想打包到 Uber JAR 中的库中的文件。
    不要添加策略:不要向 Uber JAR 添加一些包。
    例如:spark-core 已经存在存在于您的 Spark 集群中。所以我们不应该将它打包在 Uber JAR 中

    合并策略和丢弃策略基本代码:

    assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first }

    因此,您要求使用此命令 MergeStrategy.discard 丢弃 META-INF 文件,对于其余文件,如果使用此命令存在任何冲突,您将使用库文件的第一次出现 MergeStrategy.first.

    不要添加策略基本代码:

    libraryDependencies += "org.apache.spark" %% "spark-core" % "1.4.1" %"provided"

    如果我们不想将 spark-core 添加到我们的 Uber JAR 文件中,因为它已经在我们的集群中,所以我们在它库依赖项的末尾添加 % "provided"

  3. 构建 Uber JAR 及其所有依赖项

    在终端类型sbt assembly 用于构建包


瞧!!!构建了 Uber JAR。 JAR 将位于 ProjectName/target/scala-XX

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 2019-07-16
    • 1970-01-01
    • 2014-09-19
    • 2015-12-27
    相关资源
    最近更新 更多