Come build un Uber JAR (Fat JAR) usando SBT all’interno di IntelliJ IDEA?

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

Mi piacerebbe sapere qual è il modo più semplice per build un file Uber JAR (aka Fat JAR, Super JAR).

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

Eccezione nel thread “main” java.lang.SecurityException: digest di file di firma non valido per gli attributi principali di manifest

O questo errore durante il tempo di compilazione:

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

    Sembra che alcune delle mie dipendenze includano file di firma (META-INF) che devono essere rimossi nel file finale Uber JAR.

    Ho provato ad usare il plugin 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 di SBT e non molto sperimentato con IntelliJ IDE.

    Grazie.

    Infine, evito completamente di utilizzare IntelliJ IDEA per evitare di generare rumore nella mia comprensione globale 🙂

    Ho iniziato a leggere il tutorial SBT ufficiale .

    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 . Permettendomi di build un JAR grasso:

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

    Il mio build.sbt minimo sembra:

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

    Nota : il % "provided" significa non includere la dipendenza nel JAR di grasso finale (quelle librerie sono già incluse nei miei lavoratori)

    Nota : scartare META-INF ispirato a questo risponditore .

    Nota : significato di % e %%

    Ora posso build il mio JAR grasso usando SBT ( come installarlo ) eseguendo il seguente comando nella mia cartella principale / my-project :

     sbt assembly 

    Il mio JAR grasso ora si trova 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 all’interno di IntelliJ IDE: come eseguire attività di assemblaggio sbt dall’interno di IntelliJ IDEA?

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

    Uber JAR / Fat JAR : file JAR che contiene tutte le dipendenze di libraray esterne.

    1. Aggiunta del plug-in SBT Assembly in IntelliJ Idea

      Plugin sbt Path

      Vai al file ProjectName / project / target / plugins.sbt e aggiungi questa riga addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

    2. Aggiungere unisci, scartare e non aggiungere una strategia in build.sbt

      Costruisci il percorso sbt

      Vai al file ProjectName / build.sbt e aggiungi la strategia per il packaging di un Uber JAR

      Unisci strategia: se c’è un conflitto in due pacchetti su una versione della libreria, quale deve essere impacchettato in Uber JAR.
      Strategia di eliminazione : per rimuovere alcuni file dalla libreria che non si desidera includere nel pacchetto Uber JAR.
      Non aggiungere strategia: non aggiungere alcun pacchetto a Uber JAR.
      Per esempio: spark-core sarà già presente nel tuo Spark Cluster. Quindi non dovremmo comprarlo in Uber JAR

      Unisci strategia e scarta strategia Codice base:

      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.discard e per il resto dei file stai prendendo la prima occorrenza del file della libreria se c’è qualche conflitto usando questo comando MergeStrategy.first .

      Non aggiungere codice di base per la strategia:

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

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

    3. Costruire Uber JAR con tutte le sue dipendenze

      sbtassembly

      Nel tipo di terminale sbt assembly per la creazione del pacchetto

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

    JarBuilt

    Aggiungi la seguente riga al tuo progetto / plugins.sbt

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

    Aggiungi quanto segue al tuo 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 fusione degli assiemi viene utilizzata per risolvere i conflitti che si sono verificati durante la creazione del contenitore di grassi.