Как построить Uber JAR (FAT JAR) с использованием SBT в IntelliJ IDEA?

Я использую SBT (внутри IntelliJ IDEA) для создания простого проекта Scala.

Я хотел бы знать, что является простейшим способом для создания файла Uber JAR (также называемого Fat JAR, Super JAR).

В настоящее время я использую SBT, но когда я отправляю свой JAR файл в Apache Spark, я получаю следующую ошибку:

Исключение в потоке "main" java.lang.SecurityException: Недействительный сигнатурный дайджест файлов для основных атрибутов

Или эта ошибка во время компиляции:

java.lang.RuntimeException: deduplicate: найдено другое содержимое файла в следующем:
PATH\DEPENDENCY.jar: META-INF/ЗАВИСИМОСТИ
PATH\DEPENDENCY.jar: META-INF/MANIFEST.MF

Он выглядит как, потому что некоторые из моих зависимостей включают файлы подписи (META-INF), которые необходимо удалить в финальном файле Uber JAR.

Я попытался использовать плагин 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"
    )
  )

Когда я нажимаю "Build Artifact..." в IntelliJ IDEA, я получаю файл JAR. Но в итоге я получаю ту же ошибку...

Я новичок в SBT и не очень экспериментировал с IntelliJ IDE.

Спасибо.

Ответ 1

Наконец, я полностью пропускаю использование IntelliJ IDEA, чтобы избежать генерации шума в моем глобальном понимании:)

Я начал читать официальный официальный учебник SBT.

Я создал свой проект со следующей структурой:

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

Добавлен sbt-assembly plugin в мой файл assembly.sbt. Позвольте мне построить толстый 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 отбрасывает вдохновленный этим анонсом.

Примечание: значение % и %%

Теперь я могу построить свой полный JAR, используя SBT (как установить его), выполнив следующую команду в моем /my- project:

sbt assembly

Мой толстый JAR теперь находится в новой сгенерированной папке /target:

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

Надеюсь, что это поможет кому-то другому.


Для тех, кто хочет внедрить SBT в IntelliJ IDE: Как запустить задачи сборки sbt из IntelliJ IDEA?

Ответ 2

3 Шаг процесса для сборки JAR JAR/FAT JAR в IntelliJ Идея:

Uber JAR/Fat JAR: файл JAR, имеющий все внешние зависимости между библиотеками.

  • Добавление плагина сборки SBT в Idea IntelliJ

    Плагин sbt Path

    Перейдите в файл ProjectName/project/target/plugins.sbt и добавьте эту строку addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  • Добавление слияния, удаления и не добавления стратегии в build.sbt

    Build sbt Path

    Перейдите в файл ProjectName/build.sbt и добавьте Стратегию упаковки Uber 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 }

    Итак, вы просите отказаться от файлов META-INF с помощью этой команды MergeStrategy.discard, а для остальной части файлов вы берете первое вхождение файла библиотеки, если есть конфликт, используя эту команду MergeStrategy.first.

    Не добавлять основной код стратегии:

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

    Если мы не хотим добавлять искровое ядро ​​в наш Uber файл JAR, так как он уже находится на нашем clutser, поэтому мы добавляем % "provided" в конце его зависимости от библиотеки.

  • Строительство Uber JAR со всеми его зависимостями

    sbtassembly

    В терминальном типе sbt assembly для создания пакета


Вуаля!!! Uber JAR построен. JAR будет в ProjectName/target/scala -XX

JarBuilt

Ответ 3

Добавьте в проект следующую строку /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
}

Стратегия слияния сборки используется для разрешения конфликтов, возникающих при создании контейнера с жиром.