Como construir um Uber JAR (Fat JAR) usando SBT dentro do IntelliJ IDEA?

90

Estou usando o SBT (dentro do IntelliJ IDEA) para construir um projeto Scala simples.

Gostaria de saber qual é a maneira mais simples de construir um arquivo Uber JAR (também conhecido como Fat JAR, Super JAR).

No momento, estou usando o SBT, mas quando envio meu arquivo JAR para o Apache Spark , recebo o seguinte erro:

Exceção no thread "main" java.lang.SecurityException: Resumo do arquivo de assinatura inválido para atributos principais do Manifest

Ou este erro durante o tempo de compilação:

java.lang.RuntimeException: deduplicate: diferentes conteúdos de arquivo encontrados no seguinte:
PATH \ DEPENDENCY.jar: META-INF / DEPENDENCIES
PATH \ DEPENDENCY.jar: META-INF / MANIFEST.MF

Ele parece que é porque alguns dos meus dependências incluem arquivos de assinatura (META-INF), que precisa ser removido no final do arquivo JAR Uber.

Tentei usar o plug - in sbt-assembly assim:

/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 clico em " Build Artifact ... " no IntelliJ IDEA, recebo um arquivo JAR. Mas acabo com o mesmo erro ...

Sou novo no SBT e não tenho muita experiência com o IntelliJ IDE.

Obrigado.

Yves M.
fonte
2
Pelo que parece, você pode precisar filtrar os META-INFarquivos - uma postagem de blog que pode ajudar: janschulte.wordpress.com/2014/03/20/…
Sean Vieira

Respostas:

144

Finalmente, pulo totalmente o uso do IntelliJ IDEA para evitar a geração de ruído no meu entendimento global :)

Comecei a ler o tutorial oficial do SBT .

Criei meu projeto com a seguinte estrutura de arquivos:

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

Adicionado o plug - in sbt-assembly no meu arquivo assembly.sbt . Permitindo-me construir um JAR gordo:

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

Meu build.sbt mínimo se parece com:

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 : O % "provided"meio para não incluir a dependência no JAR fat final (essas bibliotecas já estão incluídas em meus trabalhos)

Nota : Descartando META-INF inspirado por este respondedor .

Nota : Significado de %e%%

Agora posso construir meu JAR gordo usando SBT ( como instalá-lo ) executando o seguinte comando na pasta raiz my / my-project :

sbt assembly

Meu JAR gordo agora está localizado na nova pasta gerada / alvo :

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

Espero que ajude outra pessoa.


Para aqueles que desejam incorporar o SBT no IntelliJ IDE: Como executar tarefas de montagem sbt de dentro do IntelliJ IDEA?

Yves M.
fonte
2
Sugestão de Java / Maven sobre o [problema de excluir Spark de uber-jars de Databricks databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
JimLohse
1
Qual é o motivo para descartar o antigo META-INF?
qed
2
Nota: O% "fornecido" significa não incluir a dependência no fat final do JAR que me ajudou!
Jayasagar
seriamente surpreso que este seja o único plugin disponível - nem mesmo oficial, e nem mesmo funciona em versões sbt
Abhinandan Dubey
40

Processo de 3 etapas para construir Uber JAR / Fat JAR no IntelliJ Idea:

Uber JAR / Fat JAR : arquivo JAR contendo todas as dependências de biblioteca externa.

  1. Adicionando plugin SBT Assembly no IntelliJ Idea

    Caminho sbt do plug-in

    Vá para o arquivo ProjectName / project / target / plugins.sbt e adicione esta linhaaddSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. Adicionando estratégia Merge, Discard e Do Not Add em build.sbt

    Construir caminho sbt

    Vá para o arquivo ProjectName / build.sbt e adicione a Estratégia para Empacotamento de um Uber JAR

    Estratégia de fusão: Se houver conflito em dois pacotes sobre uma versão da biblioteca, qual deles deve ser embalado no Uber JAR.
    Estratégia de descarte: Remover alguns arquivos da biblioteca que você não deseja empacotar no Uber JAR.
    Não adicione estratégia: Não adicione algum pacote ao Uber JAR.
    Por ex: spark-corejá estará presente no seu Spark Cluster. Portanto, não devemos empacotar isso no Uber JAR

    Estratégia de fusão e código básico de estratégia de descarte:

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

    Portanto, você está pedindo para descartar os arquivos META-INF usando este comando MergeStrategy.discarde, para o restante dos arquivos, você está pegando a primeira ocorrência do arquivo de biblioteca se houver algum conflito ao usar este comando MergeStrategy.first.

    Não adicione código básico de estratégia:

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

    Se não quisermos adicionar o spark-core ao nosso arquivo Uber JAR, pois ele já estará em nosso clutser, estamos adicionando a % "provided"dependência da biblioteca no final dele.

  3. Construindo Uber JAR com todas as suas dependências

    sbtassembly

    No tipo de terminal sbt assemblypara construir o pacote


Voila !!! O Uber JAR é construído. JAR estará em ProjectName / target / scala-XX

JarBuilt

Ajay Gupta
fonte
16

Adicione a seguinte linha ao seu projeto / plugins.sbt

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

Adicione o seguinte ao seu 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
}

A estratégia de mesclagem de montagem é usada para resolver conflitos ocorridos durante a criação de jar de gordura.

ARMV
fonte
1
Você pode criar o Fat Jar executando "sbt assembly" no console
ARMV
2
para scala versão 2.11.8 (versão SBT: 0.13.12) coloque addSbtPlugin ("com.eed3si9n"% "sbt-assembly"% "0.12.0") em project / assembly.sbt
ARMV