ฉันจะใส่ไฟล์ JAR ที่จำเป็นทั้งหมดในโฟลเดอร์ไลบรารีภายในไฟล์ JAR สุดท้ายด้วย Maven ได้อย่างไร


105

ฉันใช้ Maven ในแอปพลิเคชันแบบสแตนด์อโลนของฉันและฉันต้องการรวมการอ้างอิงทั้งหมดในไฟล์ JAR ของฉันไว้ในโฟลเดอร์ไลบรารีดังที่กล่าวไว้ในคำตอบข้อใดข้อหนึ่งที่นี่:

ฉันจะสร้าง JAR ที่ปฏิบัติการได้โดยใช้ Maven ได้อย่างไร

ฉันต้องการให้ไฟล์ JAR สุดท้ายของฉันมีโฟลเดอร์ไลบรารีที่มีการอ้างอิงเป็นไฟล์ JAR ไม่ใช่เหมือนกับสิ่งmaven-shade-pluginที่ทำให้การอ้างอิงในรูปแบบของโฟลเดอร์เช่นลำดับชั้น Maven ในโฟลเดอร์. m2

ที่จริงแล้วการกำหนดค่าปัจจุบันทำในสิ่งที่ฉันต้องการ แต่ฉันมีปัญหากับการโหลดไฟล์ JAR เมื่อเรียกใช้แอปพลิเคชัน ฉันโหลดคลาสไม่ได้

นี่คือการกำหนดค่าของฉัน:

<plugins>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>false</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

โปรเจ็กต์ทำงานได้ดีจาก Eclipse และไฟล์ JAR จะถูกใส่ในโฟลเดอร์ไลบรารีภายในไฟล์ JAR สุดท้ายของฉันตามที่ฉันต้องการ แต่เมื่อเรียกใช้ไฟล์ JAR สุดท้ายจากโฟลเดอร์เป้าหมายฉันมักจะได้รับClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.myapp.MainClass. Program will exit.

ฉันจะแก้ไขข้อยกเว้นนี้ได้อย่างไร


1
คุณใช้คำสั่งใดในการรัน jar คุณอาจชอบปลั๊กอิน maven exec หรือไม่?
Andrey Borisov

ข้อความแสดงข้อยกเว้นล้าสมัยเมื่อเทียบกับไฟล์ POM หรือไม่ ดูเหมือนว่าระดับหลักจะถูกหาไม่com.myapp.MainClass com.tastycafe.MainClass
Duncan Jones

@Duncan Jones ปัญหาการคัดลอกวางฉันแก้ไขคำถาม
Mahmoud Saleh

3
โปรดทราบว่าหากคุณต้องการ jars ภายใน jar classloaders มาตรฐานใน Java จะไม่สามารถเข้าใจได้
Thorbjørn Ravn Andersen

จะทำให้การอ้างอิง maven ในโฟลเดอร์ lib แต่อยู่นอก JAR ได้อย่างไร
ed22

คำตอบ:


81

ต่อไปนี้เป็นวิธีแก้ปัญหาของฉัน ทดสอบว่าเหมาะกับคุณหรือไม่:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- <classpathPrefix>lib</classpathPrefix> -->
                <!-- <mainClass>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

ปลั๊กอินตัวแรกวางการอ้างอิงทั้งหมดในโฟลเดอร์เป้าหมาย / คลาส / lib และอันที่สองรวมโฟลเดอร์ไลบรารีในไฟล์ JAR สุดท้ายและกำหนดค่าManifest.mfไฟล์

แต่คุณจะต้องเพิ่มรหัสการโหลดคลาสที่กำหนดเองเพื่อโหลดไฟล์ JAR

หรือหากต้องการหลีกเลี่ยงการโหลดคลาสแบบกำหนดเองคุณสามารถใช้ "$ {project.build.directory} / lib แต่ในกรณีนี้คุณไม่มีการอ้างอิงภายในไฟล์ JAR สุดท้ายซึ่งจะเอาชนะวัตถุประสงค์

เป็นเวลาสองปีแล้วที่คำถามถูกถาม ปัญหาของไฟล์ JAR ที่ซ้อนกันยังคงมีอยู่ ฉันหวังว่ามันจะช่วยใครสักคน


1
การใช้งาน: mvn install, cd target, java -jar MyJarFile-1.0.jar
djb

ฉันคิดถึงอะไร? สิ่งนี้จะสร้างรายการคลาสพา ธ รายการที่มี "lib /" และ jar เดียวทั้งหมดจากโฟลเดอร์ lib นี่ตั้งใจหรือเปล่า? ทำไม?
gapvision

2
มันใช้งานได้หลังจากที่ฉันเปลี่ยน "$ {project.build.directory} / class / lib" เป็น $ {project.build.directory} / lib
Rajendra Thorat

1
Unfortunatelly รวมถึงการอ้างอิงที่ประกาศตามที่ให้ไว้
Philippe Gioseffi

@Rajendra ขอบคุณที่ช่วย: $ {project.build.directory} / lib
Mindaugas K.

31

อัปเดต:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 

4
สิ่งนี้ทำให้โฟลเดอร์ lib อยู่นอก jar (ซึ่งไม่ใช่สิ่งที่ฉันต้องการ) จะดีกว่าการใส่ lib ไว้ในโถหรือไม่? และวิธีการส่งมอบแอปพลิเคชันให้กับลูกค้าในกรณีนี้?
Mahmoud Saleh

มันชัดเจนมากขึ้นสำหรับฉันตอนนี้ ให้ฉันค้นหาโดย Google แต่ฉันอยากรู้ว่าทำไมคุณถึงต้องการคัดลอกไฟล์ jar การพึ่งพาทั้งหมดในโฟลเดอร์ที่ระบุภายในไฟล์ jar ที่เรียกใช้งานได้ หากไฟล์ jar ที่อ้างอิงทั้งหมดอยู่ในไฟล์ jar ทำไมคุณต้องค้นหาไฟล์เหล่านี้ในโฟลเดอร์ lib
Ahmet Karakaya

23

วิธีที่ง่ายและมีประสิทธิภาพที่สุดคือการใช้ปลั๊กอิน uber ดังนี้:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

คุณจะยกเลิกการทำให้เป็นมาตรฐานทั้งหมดในไฟล์ JAR เดียว


ใช้นอกเหนือจาก config ปัจจุบันของฉันหรือไม่ และปลั๊กอินนี้ทำอะไรกันแน่?
Mahmoud Saleh

15
ฉันไม่ต้องการให้ไฟล์ jar ของฉันมีลักษณะเช่นนี้ฉันต้องการมีการอ้างอิงทั้งหมดในโฟลเดอร์ lib ภายในไฟล์ jar เหมือนที่ netbean ทำ
มาห์มูดซาเลห์

12

บรรจุหีบห่อปฏิบัติการ Maven ปลั๊กอินที่สามารถใช้สำหรับว่าที่มีวัตถุประสงค์เพื่อการสร้างการใช้งานจาวาแบบสแตนด์อโลนที่มีการอ้างอิงทั้งหมดเป็นไฟล์ JAR ในโฟลเดอร์ที่เฉพาะเจาะจง

เพียงเพิ่มสิ่งต่อไปนี้pom.xmlใน<build><plugins>ส่วนของคุณ(อย่าลืมแทนที่ค่าmainClassตามนั้น):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

ไฟล์ JAR สร้างตั้งอยู่ที่หลังจากที่คุณเรียกtarget/<YourProjectAndVersion>-pkg.jar mvn packageการอ้างอิงเวลาคอมไพล์และรันไทม์ทั้งหมดจะรวมอยู่ในlib/โฟลเดอร์ภายในไฟล์ JAR

ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียนปลั๊กอิน


ฉันลองแล้วบอกได้เลยว่ามันใช้งานได้ ... อย่างที่คุณบอกปลั๊กอินนี้จะสร้างไฟล์ jar โดยมีไลบรารี (ไห) ลงในไดเร็กทอรี lib ใน jar ... การกำหนดค่านั้นง่ายมาก ... ฉันคิดว่ามันคืออะไร ผู้เขียนคาดหวังว่าคำถามนี้ ... ฉันจะให้คะแนนแก่คุณ ... ข้อเสียเปรียบเพียงประการเดียวที่ฉันพบ (นั่นคือเหตุผลที่ฉันไม่สามารถใช้คำถามนี้ได้) มีความล่าช้าเมื่อฉันดำเนินการ jar และแอปพลิเคชันปรากฏขึ้น (ประมาณ 20 วินาที) อาจเป็นเพราะกระบวนการลงทะเบียน libs ใน classloader ที่กำหนดเอง ... แต่เป็นแนวทางที่ยอดเยี่ยมและปลั๊กอินที่ยอดเยี่ยม ...
Adam M. Gamboa G.

5

ตามลิงค์นี้:

วิธีการ: Eclipse Maven ติดตั้ง build jar ที่มีการอ้างอิง

ฉันพบว่านี่ไม่ใช่วิธีแก้ปัญหาที่ใช้งานได้เนื่องจากตัวโหลดคลาสไม่โหลดไหจากภายในไหดังนั้นฉันคิดว่าฉันจะคลายการอ้างอิงภายในโถ


3

นี่คือวิธีการ:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

จากนั้นฉันก็วิ่ง:

mvn assembly:assembly

1
โปรดทราบว่าคุณควรคอมไพล์ก่อนมือเสมอเพราะassemblyจะใส่สิ่งที่อยู่ใน "เป้าหมาย / คลาส" ใน JAR เพื่อให้แน่ใจว่า JAR มีการเปลี่ยนแปลงที่คุณเพิ่งทำกับซอร์สโค้ด ดังนั้นคุณควรทำสิ่งต่างๆเช่น: mvn clean compile assembly:assembly.
naXa

2

ฉันพบคำตอบสำหรับคำถามนี้:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

ไม่เพียง แต่คุณจะได้รับไฟล์ lib ที่ขึ้นต่อกันในโฟลเดอร์ lib แต่คุณยังได้รับ bin director ที่มีทั้ง unix และ dos ที่สามารถเรียกใช้งานได้

ในที่สุดไฟล์ปฏิบัติการจะเรียก java ด้วยอาร์กิวเมนต์ a -cp ที่แสดงรายการ libs ที่ขึ้นอยู่กับคุณทั้งหมดด้วย

ล็อตทั้งหมดอยู่ในโฟลเดอร์ appasembly ภายในโฟลเดอร์เป้าหมาย มหากาพย์

============= ใช่ฉันรู้ว่านี่เป็นกระทู้เก่า แต่ก็ยังคงมีผลการค้นหาสูงดังนั้นฉันคิดว่ามันอาจช่วยใครบางคนอย่างฉันได้


1

นี่เป็นปัญหาของ classpath อย่างชัดเจน พิจารณาว่า classpath ต้องเปลี่ยนแปลงเล็กน้อยเมื่อคุณเรียกใช้โปรแกรมของคุณนอก IDE เนื่องจาก IDE โหลด JAR อื่นที่สัมพันธ์กับโฟลเดอร์รูทของโปรเจ็กต์ของคุณในขณะที่ในกรณีของ JAR สุดท้ายมักจะไม่เป็นจริง

สิ่งที่ฉันชอบทำในสถานการณ์เหล่านี้คือสร้าง JAR ด้วยตนเอง ฉันใช้เวลามากที่สุด 5 นาทีและจะแก้ปัญหาได้เสมอ ฉันไม่แนะนำให้คุณทำเช่นนี้ หาวิธีใช้ Maven นั่นคือจุดประสงค์


@SoboLAN การสร้าง JAR ด้วยตนเองไม่ใช่วิธีแก้ปัญหาที่นี่ ความตั้งใจที่จะใช้ Maven ซึ่งตรงข้ามกับ "คู่มือ"!
Duncan Jones

@DuncanJones คุณพูดถูกทั้งหมด ฉันขอแนะนำให้เขาใช้ Maven ในการทำ อย่างไรก็ตามฉันไม่มีประสบการณ์กับมันและไม่รู้ว่าจะแนะนำวิธีแก้ปัญหาอะไร ฉันแก้ไขคำตอบเพื่อสะท้อนสิ่งนี้
Radu Murzea
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.