¿Cómo construir un Uber JAR (Fat JAR) usando SBT dentro de IntelliJ IDEA?

92

Estoy usando SBT (dentro de IntelliJ IDEA) para construir un proyecto Scala simple.

Me gustaría saber cuál es la forma más sencilla de crear un archivo JAR de Uber (también conocido como Fat JAR, Super JAR).

Actualmente estoy usando SBT pero cuando envío mi archivo JAR a Apache Spark , aparece el siguiente error:

Excepción en el hilo "principal" java.lang.SecurityException: resumen de archivo de firma no válido para los atributos principales del manifiesto

O este error durante el tiempo de compilación:

java.lang.RuntimeException: deduplicate: diferentes contenidos de archivos encontrados en lo siguiente:
PATH \ DEPENDENCY.jar: META-INF / DEPENDENCIES
PATH \ DEPENDENCY.jar: META-INF / MANIFEST.MF

Se parece que se debe a que algunos de mis dependencias incluyen archivos de firma (META-INF) que debe ser eliminado en el archivo final JAR Uber.

Traté de usar el complemento sbt-assembly así:

/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"
    )
  )

Cuando hago clic en " Build Artifact ... " en IntelliJ IDEA, obtengo un archivo JAR. Pero termino con el mismo error ...

Soy nuevo en SBT y no tengo mucha experiencia con IntelliJ IDE.

Gracias.

Yves M.
fuente
2
Por lo que parece, es posible que deba filtrar los META-INFarchivos, una publicación de blog que podría ayudar: janschulte.wordpress.com/2014/03/20/…
Sean Vieira

Respuestas:

147

Finalmente, omito totalmente el uso de IntelliJ IDEA para evitar generar ruido en mi comprensión global :)

Empecé a leer el tutorial oficial de SBT .

Creé mi proyecto con la siguiente estructura de archivos:

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

Se ha añadido el SBT-ensamblaje de plugins en mi assembly.sbt archivo. Permitiéndome construir un JAR gordo:

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

Mi build.sbt mínimo se ve así:

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
   }
}

Nota : Los % "provided"medios para no incluir la dependencia en el JAR fat final (esas bibliotecas ya están incluidas en mis trabajadores)

Nota : Descarte de META-INF inspirado en esta respuesta .

Nota : Significado de %y%%

Ahora puedo construir mi fat JAR usando SBT ( cómo instalarlo ) ejecutando el siguiente comando en mi carpeta raíz / my-project :

sbt assembly

Mi fat JAR ahora se encuentra en la nueva carpeta generada / target :

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

Espero que ayude a alguien más.


Para aquellos que desean incrustar SBT dentro de IntelliJ IDE: ¿Cómo ejecutar tareas de ensamblaje de sbt desde IntelliJ IDEA?

Yves M.
fuente
2
Sugerencia de Java / Maven sobre el [problema de excluir Spark de uber-jars de Databricks databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
JimLohse
5
El enlace adecuado de @JimLohse es databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
Zeke Fast
1
¿Cuál es la razón para descartar el META-INF antiguo?
qed
2
Nota: ¡El% "proporcionado" significa no incluir la dependencia en el JAR gordo final es lo que me ayudó!
Jayasagar
seriamente sorprendido de que este sea el único complemento disponible, ni siquiera oficial, y ni siquiera funciona en las versiones de sbt
Abhinandan Dubey
40

Proceso de 3 pasos para construir Uber JAR / Fat JAR en IntelliJ Idea:

Uber JAR / Fat JAR : archivo JAR que tiene todas las dependencias de libraray externas.

  1. Agregar el complemento SBT Assembly en IntelliJ Idea

    Ruta del plugin sbt

    Vaya al archivo ProjectName / project / target / plugins.sbt y agregue esta líneaaddSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. Adición de la estrategia Combinar, Descartar y No agregar en build.sbt

    Construir ruta sbt

    Vaya al archivo ProjectName / build.sbt y agregue la estrategia para empaquetar un JAR de Uber

    Fusionar estrategia: si hay un conflicto en dos paquetes sobre una versión de la biblioteca, entonces cuál empacar en Uber JAR.
    Descartar estrategia: para eliminar algunos archivos de la biblioteca que no desea empaquetar en Uber JAR.
    No agregue estrategia: no agregue ningún paquete a Uber JAR.
    Por ejemplo: spark-coreya estará presente en su Spark Cluster, así que no debemos empaquetar esto en Uber JAR

    Código básico de estrategia de fusión y estrategia de descarte:

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

    Por lo tanto, está pidiendo descartar los archivos META-INF usando este comando MergeStrategy.discardy para el resto de los archivos está tomando la primera aparición del archivo de biblioteca si hay algún conflicto al usar este comando MergeStrategy.first.

    No agregue el código básico de la estrategia:

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

    Si no queremos agregar el spark-core a nuestro archivo JAR de Uber, ya que ya estará en nuestro clutser, entonces agregaremos la % "provided"dependencia de biblioteca al final.

  3. Construyendo Uber JAR con todas sus dependencias

    montaje

    En tipo de terminal sbt assemblypara construir el paquete


Voila !!! Uber JAR está construido. JAR estará en ProjectName / target / scala-XX

JarBuilt

Ajay Gupta
fuente
16

Agregue la siguiente línea a su proyecto / plugins.sbt

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

Agregue lo siguiente a su 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
}

La estrategia de fusión de ensamblajes se utiliza para resolver los conflictos que se produjeron al crear fat jar.

ARMV
fuente
1
Puede crear Fat Jar ejecutando "sbt assembly" en la consola
ARMV
2
para scala versión 2.11.8 (versión SBT: 0.13.12) coloque addSbtPlugin ("com.eed3si9n"% "sbt-assembly"% "0.12.0") en project / assembly.sbt
ARMV