Come costruire un Uber JAR (Fat JAR) utilizzando SBT all'interno di IntelliJ IDEA?


90

Sto usando SBT (all'interno di IntelliJ IDEA) per costruire un semplice progetto Scala.

Vorrei sapere qual è il modo più semplice per creare un file JAR Uber (noto anche come Fat JAR, Super JAR).

Attualmente sto utilizzando SBT ma quando invio il mio file JAR ad Apache Spark ottengo il seguente errore:

Eccezione nel thread "main" java.lang.SecurityException: digest del file della firma non valido per gli attributi principali del manifesto

O questo errore durante la compilazione:

java.lang.RuntimeException: deduplicate: diversi contenuti di file trovati nel seguente:
PATH \ DEPENDENCY.jar: META-INF / DEPENDENCIES
PATH \ DEPENDENCY.jar: META-INF / MANIFEST.MF

E sembra che sia perché alcuni dei miei dipendenze includono file di firma (META-INF), che deve essere rimosso nel file JAR finale Uber.

Ho provato a utilizzare il plug -in sbt-assembly in questo modo:

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

Quando faccio clic su " Build Artifact ... " in IntelliJ IDEA ottengo un file JAR. Ma finisco con lo stesso errore ...

Sono nuovo in SBT e non ho molto sperimentato con IntelliJ IDE.

Grazie.


2
A quanto pare potresti dover filtrare i META-INFfile - un post sul blog che potrebbe aiutare: janschulte.wordpress.com/2014/03/20/…
Sean Vieira

Risposte:


144

Alla fine ho completamente saltato l'utilizzo di IntelliJ IDEA per evitare di generare rumore nella mia comprensione globale :)

Ho iniziato a leggere il tutorial ufficiale di SBT .

Ho creato il mio progetto con la seguente struttura di file:

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

Aggiunto il plugin sbt-assembly nel mio file assembly.sbt . Consentendomi di costruire un vaso grasso:

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

Il mio build.sbt minimo ha il seguente aspetto:

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 : i % "provided"mezzi per non includere la dipendenza nel JAR fat finale (quelle librerie sono già incluse nei miei worker)

Nota : META-INF scartando ispirato a questo risponditore .

Nota : significato di %e%%

Ora posso costruire il mio fat JAR usando SBT ( come installarlo ) eseguendo il seguente comando nella cartella principale del mio / mio progetto :

sbt assembly

Il mio fat JAR si trova ora nella nuova cartella generata / di destinazione :

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

Spero che aiuti qualcun altro.


Per coloro che desiderano incorporare SBT in IntelliJ IDE: come eseguire attività di assemblaggio sbt dall'interno di IntelliJ IDEA?


2
Suggerimento Java / Maven sul [problema di escludere Spark da uber-jars da Databricks databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
JimLohse


1
Qual è il motivo per scartare il vecchio META-INF?
qed

2
Nota: la% "fornita" significa non includere la dipendenza nel JAR grasso finale è quello che mi ha aiutato!
Jayasagar,

seriamente sorpreso dal fatto che questo sia l'unico plugin disponibile - nemmeno ufficiale, e non funziona nemmeno con le versioni sbt
Abhinandan Dubey

40

Processo in 3 fasi per la creazione di Uber JAR / Fat JAR in IntelliJ Idea:

Uber JAR / Fat JAR : file JAR contenente tutte le dipendenze della libreria esterna.

  1. Aggiunta del plug-in di assemblaggio SBT in IntelliJ Idea

    Plugin sbt Path

    Vai a ProjectName / project / target / plugins.sbt e aggiungi questa rigaaddSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. Aggiunta di strategie Unisci, Elimina e Non aggiungere in build.sbt

    Crea percorso sbt

    Vai a file ProjectName / build.sbt e aggiungi la strategia per la creazione di pacchetti di un JAR Uber

    Strategia di unione: in caso di conflitto in due pacchetti su una versione della libreria, quale comprimere in Uber JAR.
    Strategia di eliminazione : per rimuovere alcuni file dalla libreria che non si desidera includere in un pacchetto in Uber JAR.
    Non aggiungere strategia: non aggiungere alcun pacchetto a Uber JAR.
    Ad esempio: spark-coresarà già presente nel tuo cluster Spark, quindi non dovremmo impacchettarlo in Uber JAR

    Unisci il codice di base della strategia e della strategia di scarto:

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

    Quindi stai chiedendo di scartare i file META-INF usando questo comando MergeStrategy.discarde per il resto dei file stai prendendo la prima occorrenza del file di libreria se c'è qualche conflitto usando questo comando MergeStrategy.first.

    Non aggiungere codice di base della strategia:

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

    Se non vogliamo aggiungere lo spark-core al nostro file JAR Uber poiché sarà già sul nostro clutser, stiamo aggiungendo la % "provided"dipendenza della libreria alla fine.

  3. Costruire Uber JAR con tutte le sue dipendenze

    sbtassembly

    Nel tipo di terminale sbt assemblyper la creazione del pacchetto


Ecco!!! Uber JAR è stato creato. JAR sarà in ProjectName / target / scala-XX

JarBuilt


16

Aggiungi la seguente riga al tuo progetto / plugins.sbt

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

Aggiungi quanto segue al tuo file 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 strategia di unione degli assembly viene utilizzata per risolvere i conflitti verificatisi durante la creazione di fat jar.


1
Puoi creare Fat Jar eseguendo "sbt assembly" nella console
ARMV

2
per la versione scala 2.11.8 (versione SBT: 0.13.12) inserire addSbtPlugin ("com.eed3si9n"% "sbt-assembly"% "0.12.0") in project / assembly.sbt
ARMV
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.