รวมถึงการพึ่งพาในขวดที่มี Maven


353

มีวิธีบังคับ maven (2.0.9) เพื่อรวมการขึ้นต่อกันทั้งหมดในไฟล์ jar เดียวหรือไม่?

ฉันมีโครงการที่สร้างเป็นไฟล์ jar เดียว ฉันต้องการให้คลาสจากการอ้างอิงถูกคัดลอกลงใน jar เช่นกัน

อัปเดต:ฉันรู้ว่าฉันไม่สามารถรวมไฟล์ jar ในไฟล์ jar ได้ ฉันกำลังค้นหาวิธีที่จะแกะขวดที่ระบุเป็นการอ้างอิงและจัดเก็บไฟล์คลาสไว้ในขวดของฉัน




2
จะรวมไฟล์ jar ไว้ในไฟล์ jar ใน maven ได้อย่างไร
เทือกเขาฮินดูกูช Patel

คำตอบ:


488

คุณสามารถทำได้โดยใช้ปลั๊กอินชุดคำสั่ง maven ด้วยตัวอธิบาย "jar-with-dependencies" นี่คือ chunk ที่เกี่ยวข้องจากหนึ่งใน pom.xml ของเราซึ่งทำสิ่งนี้:

  <build>
    <plugins>
      <!-- any other plugins -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

30
attachedเป้าหมายจะเลิก singleหรือdirectory-singleเป้าหมายที่ควรได้รับการแนะนำแทน
Pascal Thivent

16
directory-singleเลิกใช้แล้วเช่นกัน
James McMahon

14
แนะนำให้ใช้singleบนเว็บไซต์
mateuszb

42
ในกรณีที่คน mvn ใหม่ติดอยู่เหมือนฉันให้เพิ่มปลั๊กอินไปยัง <plugins> ภายใน <build> ซึ่งอยู่ใน <project>
DA

10
@ Christian.tucker มี jar ตัวที่สองในไดเรกทอรีเป้าหมายที่สร้างเช่นนี้: ./target/example-0.0.1-SNAPSHOT.jar และ . /target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
ช่างเทคนิค

145

ด้วย Maven 2 วิธีที่ถูกต้องคือการใช้Maven2 Assembly Pluginซึ่งมีไฟล์ descriptor ที่กำหนดไว้ล่วงหน้าสำหรับวัตถุประสงค์นี้และคุณสามารถใช้บนบรรทัดคำสั่ง:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

หากคุณต้องการทำให้ jar นี้สามารถเรียกใช้งานได้เพียงเพิ่มคลาสหลักเพื่อเรียกใช้การกำหนดค่าปลั๊กอิน:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

หากคุณต้องการสร้างแอสเซมบลีนั้นเป็นส่วนหนึ่งของกระบวนการสร้างปกติคุณควรผูกเป้าหมายเดียวหรือไดเรกทอรีเดียว ( assemblyเป้าหมายควรจะเรียกใช้จากบรรทัดคำสั่งเท่านั้น) ไปยังขั้นตอนวงจรชีวิต ( packageเหมาะสม) ดังนี้:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>create-my-bundle</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

ปรับconfigurationองค์ประกอบให้เหมาะกับความต้องการของคุณ (ตัวอย่างเช่นสิ่งที่ประจักษ์ตามที่พูด)


ฉันพยายามอย่างนี้ แต่ปลั๊กอินไม่ทำงานและไฟล์ jar ไม่ได้ถูกสร้างขึ้นแม้ว่าการสร้างจะดำเนินการได้อย่างราบรื่น มีข้อผิดพลาดทั่วไปที่ฉันอาจติดอยู่กับอะไร?
posdef

6
มันใช้งานได้สำหรับฉัน แต่มีภารกิจ หลังจากสร้างตอนนี้สองขวดจะถูกสร้างขึ้นหนึ่งขวดที่มีโครงการ artifactid-version และอีกขวดหนึ่งที่มี artifactid-version- "jar-with-dependencies" แต่ฉันต้องการเพียงขวดเดียวที่จะสร้าง มีวิธีอื่นอีก
ไหม

38

หากคุณต้องการทำไฟล์ jar ที่สามารถเรียกใช้งานได้พวกเขาจำเป็นต้องตั้งคลาสหลักด้วย ดังนั้นการกำหนดค่าเต็มควรจะเป็น

    <plugins>
            <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
                  <configuration>
                       <!-- ... -->
                       <archive>
                           <manifest>
                                 <mainClass>fully.qualified.MainClass</mainClass>
                           </manifest>
                       </archive>
                       <descriptorRefs>
                           <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                 </configuration>
         </plugin>
   </plugins>

2
ทำไมชื่อของ jar จึงต่อท้ายด้วย "jar-with-dependencies"! วิธีแก้ปัญหาใด ๆ
Tina J

1
@Tina J คุณสามารถเพิ่ม<appendAssemblyId>false</appendAssemblyId>ภายใน<configuration>แท็กเพื่อยกเว้นส่วนต่อท้าย "-jar-with-dependencies" ในชื่อสุดท้าย
ccu

19

มีเป็นปลั๊กอินที่ร่ม Maven มันสามารถใช้ในการแพคเกจและเปลี่ยนชื่อการอ้างอิง (เพื่อละเว้นปัญหาการพึ่งพาใน classpath)


2
หากคุณไม่ชอบ jar-with-dependencies เป็นส่วนหนึ่งของชื่อไฟล์
Kyle


นี่เป็นคำตอบที่ดีที่สุดสำหรับฉัน :) :)
Anand Varkey Philips

17

คุณสามารถใช้ jar ที่สร้างขึ้นใหม่โดยใช้<classifier>แท็ก

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>

14

หากคุณ (เช่นฉัน) ไม่ชอบวิธีการjar-with-dependenciesตามที่อธิบายไว้ข้างต้น maven-solution ที่ฉันต้องการคือเพียงแค่สร้างโครงการ WAR แม้ว่ามันจะเป็นเพียงโปรแกรม Java แบบสแตนด์อะโลนที่คุณกำลังสร้าง:

  1. สร้าง jar โครงการ maven ปกติซึ่งจะสร้างไฟล์ jar ของคุณ (โดยไม่มีการอ้างอิง)

  2. นอกจากนี้ให้ตั้งค่า maven war-project (ด้วยไฟล์src / main / webapp / WEB-INF / web.xml ที่ว่างเปล่าเท่านั้นซึ่งจะหลีกเลี่ยงคำเตือน / ข้อผิดพลาดใน maven-build) ที่มี jar โครงการของคุณเป็น การพึ่งพาและทำให้โครงการ jar ของคุณเป็นโครงการ<module>สงครามของคุณ (โปรเจ็กต์สงครามนี้เป็นเพียงกลลวงอย่างง่ายในการห่อการพึ่งพาไฟล์ jar ทั้งหมดของคุณให้เป็นไฟล์ zip)

  3. สร้างโครงการสงครามเพื่อสร้างไฟล์สงคราม

  4. ในขั้นตอนการปรับใช้เพียงเปลี่ยนชื่อไฟล์. war เป็น * .zip และคลายซิป

ตอนนี้คุณควรมี lib-directory (ซึ่งคุณสามารถย้ายไปยังตำแหน่งที่คุณต้องการ) ด้วย jar ของคุณและการอ้างอิงทั้งหมดที่คุณต้องใช้ในการเรียกใช้แอปพลิเคชันของคุณ:

java -cp 'path/lib/*' MainClass

(สัญลักษณ์ตัวแทนใน classpath ทำงานได้ใน Java-6 หรือสูงกว่า)

ฉันคิดว่านี่เป็นทั้งการตั้งค่าที่ง่ายขึ้นใน maven (ไม่จำเป็นต้องยุ่งกับปลั๊กอินแอสเซมบลี) และยังช่วยให้คุณมีมุมมองที่ชัดเจนขึ้นของโครงสร้างแอปพลิเคชัน (คุณจะเห็นหมายเลขรุ่นของไห หลีกเลี่ยงการอุดตันทุกสิ่งลงในไฟล์ jar เดียว)


มันเหมือนกับ Eclipse "ส่งออกเป็น Runnable jar" หรือไม่? เพราะด้วยสิ่งนี้คุณสามารถเลือกที่จะ "จัดทำแพ็กเกจการขึ้นต่อกันทั้งหมดด้วย JAR" จากนั้นคุณจะได้รับการอ้างอิงทั้งหมดในโฟลเดอร์ project-lib พร้อมกับ jar ของคุณ
WesternGun

@FaithReaper - มันอาจจะ "เหมือนเดิม" ฉันไม่เคยลองเลย แต่ผมคิดว่าถ้าคุณใช้ Eclipse ก็ไม่ได้อย่างง่ายดายสคริปต์ซึ่งเป็นความต้องการถ้าคุณต้องการที่จะใช้อัตโนมัติสร้าง + ปรับใช้ท่อ ตัวอย่างเช่นให้ Jenkins-server สร้างจากแหล่งเก็บข้อมูล git หรือที่คล้ายกัน
รอบ

12

http://fiji.sc/Uber-JARให้คำอธิบายที่ดีเกี่ยวกับทางเลือก:

มีวิธีการทั่วไปสามวิธีในการสร้าง uber-JAR:

  1. ไม่มีเงา แกะไฟล์ JAR ทั้งหมดจากนั้นบรรจุใหม่ลงใน JAR ไฟล์เดียว
    • Pro: ทำงานร่วมกับ class loader เริ่มต้นของ Java
    • คอนดิชั่น: ไฟล์ที่มีอยู่ในไฟล์ JAR หลายไฟล์ที่มีพา ธ เดียวกัน (เช่น META-INF / services / javax.script.ScriptEngineFactory) จะเขียนทับกันทำให้เกิดพฤติกรรมที่ผิดพลาด
    • เครื่องมือ: Maven Assembly Plugin, Classworlds Uberjar
  2. สีเทา เหมือนกับ unshaded แต่เปลี่ยนชื่อ (เช่น "shade") แพ็คเกจทั้งหมดของการอ้างอิงทั้งหมด
    • Pro: ทำงานร่วมกับ class loader เริ่มต้นของ Java หลีกเลี่ยงการปะทะกันของเวอร์ชันการพึ่งพา (ไม่ใช่ทั้งหมด)
    • คอนดิชั่น: ไฟล์ที่มีอยู่ในไฟล์ JAR หลายไฟล์ที่มีพา ธ เดียวกัน (เช่น META-INF / services / javax.script.ScriptEngineFactory) จะเขียนทับกันทำให้เกิดพฤติกรรมที่ผิดพลาด
    • เครื่องมือ: Maven Shade Plugin
  3. JAR ของ JARs ไฟล์ JAR สุดท้ายมีไฟล์ JAR อื่น ๆ ที่ฝังอยู่ภายใน
    • Pro: หลีกเลี่ยงเวอร์ชันการพึ่งพา ไฟล์ทรัพยากรทั้งหมดถูกสงวนไว้
    • Con: จำเป็นต้องรวม classloader "bootstrap" พิเศษเพื่อเปิดใช้งาน Java เพื่อโหลดคลาสจากไฟล์ JAR ที่ห่อ การดีบักปัญหาตัวโหลดคลาสจะซับซ้อนมากขึ้น
    • เครื่องมือ: Eclipse JAR File Exporter, One-JAR

1
ไม่เป็นความจริงเกี่ยวกับบริการปลั๊กอินที่แรเงามีหม้อแปลงและหนึ่งในนั้นคือการเชื่อมโยงเนื้อหาของไฟล์ภายใต้META-INF/servicesไดเรกทอรี ข้อมูลเพิ่มเติมที่นี่: maven.apache.org/plugins/maven-shade-plugin/examples/ …
vitro

7
        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive> 
                <stripVersion>false</stripVersion>
            </configuration>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- Add LIB folder to classPath -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
        </plugin>            

4

โซลูชันที่ชัดเจนของฉันเกี่ยวกับ Eclipse Luna และ m2eclipse: Custom Classloader (ดาวน์โหลดและเพิ่มในโครงการของคุณ 5 คลาสเท่านั้น): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / ภายใน / jarinjarloader / ; classloader นี้ดีที่สุดของ classloader หนึ่ง jar และเร็วมาก

<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

แก้ไขใน JIJConstants "Rsrc-Class-Path" ถึง "คลาสพา ธ "
mvn การอ้างอิงใหม่ทั้งหมด: แพคเกจ copy-dependencies
ถูกสร้างขึ้น jar ที่มีการอ้างอิงในโฟลเดอร์ lib ที่มี classloader บาง ๆ

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*</include>
            </includes>
            <targetPath>META-INF/</targetPath>
        </resource>
        <resource>
            <directory>${project.build.directory}/dependency/</directory>
            <includes>
                <include>*.jar</include>
            </includes>
            <targetPath>lib/</targetPath>
        </resource>
    </resources>
<pluginManagement>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>${project.mainClass}</mainClass>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>

                        <manifestEntries>
                            <Rsrc-Main-Class>${project.realMainClass}  </Rsrc-Main-Class>
                            <Class-Path>./</Class-Path>
                        </manifestEntries>

                    </archive>
                </configuration>
            </plugin>
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

maven-dependency-plugin <outputDirectory> ไม่ทำงานเขียนบนโฟลเดอร์ "dependency"
เสมอ

สร้างขวดที่มีโฟลเดอร์ "การพึ่งพา" ภายในโฟลเดอร์ที่มีการอ้างอิงโครงการและวางไว้บน MANIFEST.MF
Glaucio Southier

<resources> <resource> <directory> src / main / java </directory> <includes> <include> ** / *. java </include> <include> ** / *. properties </include> </ รวม > </resource> <resource> <directory> src / main / resources </directory> <filtering> จริง </filtering> <includes> <includes> <include> ** / * </include> </targetPath> META -INF / </targetPath> </resource> <resource> <directory> $ {project.build.directory} / การพึ่งพา / </directory> <includes> <include> * .jar </include> </includes> < targetPath> lib / </targetPath> </resource> </resources>
Glaucio Southier

1
จากคำตอบนี้ฉันได้สร้างโครงการนี้ขึ้นมา คุณไม่จำเป็นต้องเปลี่ยนแปลงอะไรนอกจากไฟล์ pom: github.com/raisercostin/jarinjarloader
raisercostin

1

วาง Maven ไว้ข้าง ๆ คุณสามารถใส่ไลบรารี JAR ไว้ในขวดหลัก แต่คุณจะต้องใช้ classloader ของคุณเอง

ตรวจสอบโปรเจ็กต์นี้: ข้อความลิงก์ One-JAR


นอกจากนี้ยังมีปลั๊กอิน Maven สำหรับ One-JAR: onejar-maven-plugin.googlecode.com/svn/mavensite/usage.html
Thilo

0

โพสต์นี้อาจจะค่อนข้างเก่า แต่ฉันก็มีปัญหาเดียวกันเมื่อเร็ว ๆ นี้ ทางออกแรกที่เสนอโดย John Stauffer เป็นวิธีที่ดี แต่ฉันมีปัญหาบางอย่างในขณะที่ฉันกำลังทำงานในฤดูใบไม้ผลินี้ Spring-dependars-jars ที่ฉันใช้มีไฟล์คุณสมบัติและการประกาศ xml-schemas ซึ่งมีพา ธ และชื่อเดียวกัน แม้ว่าไหเหล่านี้จะมาจากเวอร์ชั่นเดียวกัน แต่jar-with-dependencies maven-target คือการเขียนทับไฟล์วิทยานิพนธ์ด้วยไฟล์ล่าสุดที่พบ

ในที่สุดแอปพลิเคชันไม่สามารถเริ่มต้นได้เนื่องจาก jars ฤดูใบไม้ผลิไม่สามารถค้นหาไฟล์คุณสมบัติที่ถูกต้อง ในกรณีนี้การแก้ปัญหาที่เสนอโดย Rop ได้แก้ไขปัญหาของฉันแล้ว

ตั้งแต่นั้นมาโครงการสปริงบูตก็มีอยู่ในขณะนี้ มันมีวิธีที่ยอดเยี่ยมในการจัดการปัญหานี้โดยจัดทำเป้าหมาย maven ซึ่งเกินเป้าหมายแพคเกจและให้ตัวโหลดคลาสของตัวเอง ดูคู่มืออ้างอิงรองเท้าบูทสปริง


0

ดูคำตอบนี้:

ฉันกำลังสร้างตัวติดตั้งที่รันเป็นไฟล์ Java JAR และจำเป็นต้องคลายไฟล์ WAR และ JAR ลงในตำแหน่งที่เหมาะสมในไดเร็กทอรีการติดตั้ง ปลั๊กอินการพึ่งพาสามารถใช้ในขั้นตอนแพ็คเกจด้วยเป้าหมายการคัดลอกและมันจะดาวน์โหลดไฟล์ใด ๆ ในที่เก็บ Maven (รวมถึงไฟล์ WAR) และเขียนพวกเขาในที่ที่คุณต้องการ ฉันเปลี่ยนไดเร็กตอรี่เอาท์พุทเป็น $ {project.build.directory} / classes แล้วผลลัพธ์ก็คืองาน JAR ปกติรวมไฟล์ของฉันไว้ด้วย ฉันสามารถแยกมันออกแล้วเขียนลงในไดเรคทอรี่การติดตั้ง

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
    <execution>
        <id>getWar</id>
        <phase>package</phase>
        <goals>
            <goal>copy</goal>
        </goals>
        <configuration>
            <artifactItems>
                <artifactItem>
                    <groupId>the.group.I.use</groupId>
                    <artifactId>MyServerServer</artifactId>
                    <version>${env.JAVA_SERVER_REL_VER}</version>
                    <type>war</type>
                    <destFileName>myWar.war</destFileName>
                </artifactItem>
            </artifactItems>
            <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
    </execution>
</executions>


0

ขอบคุณฉันได้เพิ่มตัวอย่างด้านล่างในไฟล์ POM.xml และแก้ไขปัญหา Mp และสร้างไฟล์ jar ไขมันที่มีขวดขึ้นอยู่ทั้งหมด

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <descriptorRefs>
                <descriptorRef>dependencies</descriptorRef>
            </descriptorRefs>
        </configuration>
    </plugin>
</plugins>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.