จะสร้าง Uber JAR (Fat JAR) โดยใช้ SBT ภายใน IntelliJ IDEA ได้อย่างไร


92

ฉันใช้ SBT (ภายใน IntelliJ IDEA) เพื่อสร้างโครงการ Scala อย่างง่าย

ฉันอยากทราบวิธีที่ง่ายที่สุดในการสร้างไฟล์Uber JAR (aka Fat JAR, Super JAR)

ฉันกำลังใช้ SBT แต่เมื่อฉันส่งไฟล์ JAR ไปยังApache Sparkฉันได้รับข้อผิดพลาดต่อไปนี้:

ข้อยกเว้นในเธรด "main" java.lang.SecurityException: การย่อยไฟล์ลายเซ็นไม่ถูกต้องสำหรับแอตทริบิวต์หลักของ Manifest

หรือเกิดข้อผิดพลาดระหว่างเวลาคอมไพล์:

java.lang.RuntimeException: ขจัดข้อมูลซ้ำซ้อน: พบเนื้อหาไฟล์ที่แตกต่างกันต่อไปนี้:
PATH \ DEPENDENCY.jar: META-INF / DEPENDENCIES
PATH \ DEPENDENCY.jar: META-INF / MANIFEST.MF

มันดูเหมือนว่ามันเป็นเพราะบางส่วนของการอ้างอิงของฉันรวมถึงแฟ้มลายเซ็น (META-INF) ซึ่งจะต้องออกในรอบสุดท้าย JAR ไฟล์ Uber

ฉันพยายามใช้ปลั๊กอิน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 มากนัก

ขอบคุณ.


2
ด้วยเสียงของสิ่งที่คุณอาจต้องกรองMETA-INFไฟล์ - หนึ่งบล็อกโพสต์ที่อาจช่วยได้: janschulte.wordpress.com/2014/03/20/…
Sean Vieira

คำตอบ:


147

ในที่สุดฉันก็ข้ามไปใช้ IntelliJ IDEA เพื่อหลีกเลี่ยงการสร้างเสียงรบกวนในความเข้าใจทั่วโลกของฉัน :)

ผมเริ่มอ่านSBT อย่างเป็นทางการของการกวดวิชา

ฉันสร้างโครงการด้วยโครงสร้างไฟล์ต่อไปนี้:

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

เพิ่มปลั๊กอินsbt-assembly ในไฟล์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")        
  )

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

หมายเหตุ : % "provided"วิธีการไม่รวมการพึ่งพาใน fat JAR สุดท้าย (ไลบรารีเหล่านั้นรวมอยู่ในคนงานของฉันแล้ว)

หมายเหตุ : META-INF ทิ้งแรงบันดาลใจจาก answser

หมายเหตุ : ความหมายของ%และ%%

ตอนนี้ฉันสามารถสร้าง JAR ไขมันของฉันโดยใช้ SBT ( วิธีการติดตั้ง ) โดยเรียกใช้คำสั่งต่อไปนี้ในโฟลเดอร์รูทของฉัน/ my-project :

sbt assembly

JAR ไขมันของฉันอยู่ในโฟลเดอร์ที่สร้าง/ เป้าหมายใหม่:

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

หวังว่าจะช่วยคนอื่น


สำหรับผู้ที่ต้องการยักยอก SBT ภายใน IntelliJ IDE: จะเรียกใช้งาน sbt-assembly จากภายใน IntelliJ IDEA ได้อย่างไร?


2
ข้อเสนอแนะ Java / Maven เกี่ยวกับ [ปัญหาในการยกเว้น Spark จาก uber-jars จาก Databricks databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
JimLohse

5
ลิงค์ที่เหมาะสมของ @JimLohse คือdatabricks.gitbooks.io/databricks-spark-knowledge-base/content/…
Zeke Fast

1
สาเหตุของการทิ้ง META-INF เก่าคืออะไร?
qed

2
หมายเหตุ:% "ให้" หมายความว่าไม่รวมการพึ่งพาใน JAR ไขมันสุดท้ายคือสิ่งที่ช่วยฉัน!
Jayasagar

แปลกใจอย่างมากที่นี่เป็นปลั๊กอินเดียวที่มีให้ - ไม่เป็นทางการและใช้ไม่ได้กับเวอร์ชัน sbt
Abhinandan Dubey

40

กระบวนการ 3 ขั้นตอนสำหรับการสร้าง Uber JAR / Fat JAR ใน IntelliJ Idea:

Uber JAR / Fat JAR : ไฟล์ JAR ที่มีการพึ่งพา Libraray ภายนอกทั้งหมดอยู่ในนั้น

  1. การเพิ่มปลั๊กอิน SBT Assembly ใน IntelliJ Idea

    เส้นทางปลั๊กอิน sbt

    ไปที่ไฟล์ProjectName / project / target / plugins.sbtแล้วเพิ่มบรรทัดนี้addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. การเพิ่มกลยุทธ์การผสานทิ้งและไม่เพิ่มใน build.sbt

    สร้างเส้นทาง sbt

    ไปที่ไฟล์ProjectName / build.sbtและเพิ่ม Strategy for Packaging ของ 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"

    หากเราไม่ต้องการเพิ่ม spark-core ลงในไฟล์ Uber JAR ของเราเนื่องจากมันจะอยู่ในคลัสเตอร์ของเราแล้วดังนั้นเราจึงเพิ่มส่วน% "provided"ท้ายของการพึ่งพาไลบรารี

  3. การสร้าง Uber JAR ด้วยการอ้างอิงทั้งหมด

    sbtassembly

    ในประเภทเทอร์มินัลsbt assemblyสำหรับการสร้างแพ็คเกจ


โวล่า !!! Uber JAR ถูกสร้างขึ้น JAR จะอยู่ในProjectName / target / scala-XX

โถสร้าง


16

เพิ่มบรรทัดต่อไปนี้ใน project / 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
}

กลยุทธ์การรวมแอสเซมบลีใช้เพื่อแก้ไขความขัดแย้งที่เกิดขึ้นเมื่อสร้างโถไขมัน


1
คุณสามารถสร้าง Jar ไขมันได้โดยเรียกใช้ "sbt assembly" ในคอนโซล
ARMV

2
สำหรับ scala เวอร์ชัน 2.11.8 (เวอร์ชัน SBT: 0.13.12) ให้ใส่ addSbtPlugin ("com.eed3si9n"% "sbt-assembly"% "0.12.0") ใน project / assembly.sbt
ARMV
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.