如何使用带有IntelliJ IDEA的SBT构建Uber JAR(Fat JAR)?

时间:2015-02-11 16:25:42

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

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

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

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

  

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

编译时出现此错误:

  

java.lang.RuntimeException:deduplicate:找到不同的文件内容   在以下内容中:
  PATH \ DEPENDENCY.jar:META-INF /相关内容
  PATH \ DEPENDENCY.jar:META-INF / MANIFEST.MF

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

我尝试使用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中,我得到一个JAR文件。但我最终得到了同样的错误...

我是SBT的新手,并没有经过IntelliJ IDE的实验。

感谢。

3 个答案:

答案 0 :(得分:129)

最后,我完全跳过使用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")        
  )

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-core" % "1.2.0" % "provided",
  "org.apache.spark" %% "spark-streaming" % "1.2.0" % "provided",
  "org.apache.spark" % "spark-streaming-twitter_2.10" % "1.2.0"
)

// 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?

答案 1 :(得分:38)

在IntelliJ Idea中构建Uber JAR / Fat JAR的3个步骤:

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

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

    Plugin sbt Path

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

  2. 在build.sbt中添加合并,放弃和不添加策略

    Build sbt Path

    转到 ProjectName / build.sbt 文件并添加优步JAR包装策略

    合并策略:如果两个软件包关于某个版本的库存在冲突,那么要在Uber JAR中打包哪个软件包。
    放弃策略:从库中删除一些您不想在Uber JAR中打包的文件。
    不添加策略:不要向Uber JAR添加一些软件包。
    例如:spark-core已经存在于您的Spark Cluster中。所以我们不应该在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文件中,因为它已经在我们的clutser上了,所以我们在库依赖的末尾添加了% "provided"。 / p>

  3. 构建具有所有依赖性的Uber JAR

    sbtassembly

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


  4. 瞧! Uber JAR已建成。 JAR将位于 ProjectName / target / scala-XX

    JarBuilt

答案 2 :(得分:16)

将以下行添加到项目/ 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
}

程序集合并策略用于解决创建胖jar时发生的冲突。