Câu hỏi Làm thế nào tôi có thể tạo một JAR thực thi với các phụ thuộc sử dụng Maven?


Tôi muốn đóng gói dự án của mình trong một JAR thực thi duy nhất để phân phối.

Làm thế nào tôi có thể làm cho một dự án Maven gói tất cả các phụ thuộc JAR vào JAR đầu ra của tôi?


1944
2018-02-22 08:43


gốc


Vui lòng giải thích mục tiêu của plugin phụ thuộc mà bạn đang đề cập đến. Tôi biết không có mục tiêu làm những gì mà câu hỏi ban đầu yêu cầu: để đặt tất cả các phụ thuộc hoặc A) bên trong các tác giả jar thông qua đóng gói lại, hoặc B) làm cho một jar thực thi có những người khác trong một classpath của MANIFEST.MF - Matthew McCullough
Bạn có thể thấy điều này hữu ích rationaljava.com/2015/02/… - Dan
2 ví dụ: tugay.biz/2015/12/a-standalone-java-web-application-with.html  tugay.biz/2016/11/how-did-i-create-executable-jar-with.html - Koray Tugay
Tham khảo stackoverflow.com/questions/35217128/… - Thanga


Các câu trả lời:


<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

và bạn chạy nó với

mvn clean compile assembly:single

Mục tiêu biên dịch phải được thêm vào trước khi lắp ráp: một hoặc không có mã trên dự án của riêng bạn không được bao gồm.

Xem thêm chi tiết trong phần bình luận.


Thường thì mục tiêu này được gắn với một giai đoạn xây dựng để thực thi tự động. Điều này đảm bảo JAR được xây dựng khi thực thi mvn install hoặc thực hiện triển khai / phát hành.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

1866
2017-12-01 10:46



Cảm ơn @IAdapter. Lưu ý rằng bạn nên luôn luôn làm một biên dịch trước khi bàn tay bởi vì nó sẽ chỉ đặt bất cứ điều gì là trong "mục tiêu / lớp học" trong JAR. Điều này sẽ đảm bảo rằng JAR bao gồm bất kỳ thay đổi nào bạn đã thực hiện gần đây đối với mã nguồn. Vì vậy, bạn nên làm một cái gì đó như: mvn clean compile assembly:single. - Michael
Tôi đã chỉnh sửa các câu hỏi để bao gồm các giai đoạn ràng buộc. Tôi đã loại bỏ mục tiêu lắp ráp không được chấp nhận, bởi vì không ai cần biết về điều đó. - Duncan Jones
Tôi thấy rằng điều này không thêm các lọ vào bình uber, thay vào đó, điều này chỉ thêm tất cả các tệp lớp vào jar. - pitchblack408
Mẹo: bạn cũng có thể thêm phần tử <appendAssemblyId>false</appendAssemblyId> vào configuration để tránh hậu tố "-jar-với-phụ thuộc" gây phiền nhiễu trong tên - maxivis
quên compile và bạn bị say. - prayagupd


Bạn có thể sử dụng plugin phụ thuộc để tạo tất cả các phụ thuộc trong một thư mục riêng biệt trước giai đoạn gói và sau đó bao gồm trong đường dẫn lớp của tệp kê khai:

<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}/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>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

Hoặc sử dụng ${project.build.directory}/classes/lib như OutputDirectory để tích hợp tất cả các tệp jar vào jar chính, nhưng sau đó bạn sẽ cần phải thêm mã nạp lớp tùy chỉnh để tải các lọ.


294
2018-06-02 03:01



+1 Tuyệt vời. Lý do tôi đi với plugin maven-dependency thay vì maven-assembly-plugin là tôi cũng đang sử dụng buildnumber-maven-plugin, và theo cách này tôi có thể lưu trữ số phiên bản trong tệp kê khai của từng jar riêng lẻ. - PapaFreud
Tôi thích giải pháp của bạn. tôi sử dụng ${project.build.directory}/classes/lib như outputDirectory để có một chính .jar với tất cả các phụ thuộc bên trong, nhưng - Làm thế nào để thêm mã nạp lớp tùy chỉnh để tải các lọ này? Tôi cần thực hiện công việc như: java -jar main-jar-with-deps.jar. Điều này có thể không? - marioosh
@ André Aronsen, tôi đã sử dụng giải pháp này để thêm các phụ thuộc vào một thư mục lib bên trong bình, nhưng tôi luôn luôn được lớp học không tìm thấy ngoại lệ, bạn có thể xin vui lòng tư vấn làm thế nào để sửa chữa đó. - Mahmoud Saleh
+1 cho bạn !! Có vẻ như plugin lắp ráp maven 'jar-with-dependencies' không thực sự hoạt động tốt. Tôi đã thiếu một số mục từ META-INF / spring.schemas trong jar được tạo. Vì vậy, tôi loại bỏ các phụ thuộc vào lọ và sử dụng giải pháp của bạn ở trên. Cảm ơn hoàn hảo !!! - Derek
Đối với bất cứ ai khác gặp phải vấn đề này, bạn phải bao gồm thư mục lib trong cùng thư mục với bình chứa của bạn, nơi bạn đã bao giờ vận chuyển bình. - Sparticles


Tôi viết blog về một số cách khác nhau để làm điều này.

Xem Jar thực thi với Apache Maven (WordPress)

hoặc là ví dụ thực thi-jar-với-maven (GitHub)

Ghi chú

Những ưu và khuyết điểm được cung cấp bởi Stephan.


Để triển khai thủ công

  • Ưu điểm
  • Nhược điểm
    • Phụ thuộc được ra khỏi bình cuối cùng.

Sao chép phụ thuộc vào một thư mục cụ thể

<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}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Làm cho thực thi Jar và Classpath Aware

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

Tại thời điểm này jar thực sự có thể thực thi được với các phần tử classpath bên ngoài.

$ java -jar target/${project.build.finalName}.jar

Tạo lưu trữ có thể triển khai

Các jar tệp chỉ thực thi với anh chị em ...lib/ danh mục. Chúng ta cần tạo kho lưu trữ để triển khai với thư mục và nội dung của nó.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Bây giờ bạn có target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz) cái nào chứa jar và lib/*.


Plugin lắp ráp Apache Maven

  • Ưu điểm
  • Nhược điểm
    • Không hỗ trợ di chuyển lớp (sử dụng maven-shade-plugin nếu cần di chuyển lớp).
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

Bạn có target/${project.bulid.finalName}-jar-with-dependencies.jar.


Plugin Apache Maven Shade

  • Ưu điểm
  • Nhược điểm
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Bạn có target/${project.build.finalName}-shaded.jar.


plugin onejar-maven

  • Ưu điểm
  • Nhược điểm
    • Không được hỗ trợ tích cực kể từ năm 2012.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Spring Boot Maven Plugin

  • Ưu điểm
  • Nhược điểm
    • Thêm các lớp liên quan đến Spring và Spring Boot không cần thiết tiềm năng.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

Bạn có target/${project.bulid.finalName}-spring-boot.jar.


134
2018-02-26 04:31



Người duy nhất làm việc cho tôi là triển khai thủ công. - caiohamamura
@caiohamamura Bạn có thể sao chép Kho lưu trữ GitHub và xem cách tất cả các cấu hình hoạt động. - Jin Kwon
Vấn đề là với gói tôi đang sử dụng: stackoverflow.com/a/12622037/2548351 - caiohamamura


Lấy câu trả lời của Unanswered và định dạng lại nó, chúng ta có:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

Tiếp theo, tôi khuyên bạn nên làm cho phần này trở thành một phần tự nhiên của bản dựng của bạn chứ không phải cái gì đó để gọi một cách rõ ràng. Để làm cho phần này trở thành một phần không thể thiếu trong bản dựng của bạn, hãy thêm plugin này vào pom.xml và liên kết nó với package sự kiện vòng đời. Tuy nhiên, một điều khó hiểu là bạn cần phải gọi assembly:single mục tiêu nếu đặt điều này trong tệp pom.xml của bạn, trong khi bạn sẽ gọi 'assembly: assembly' nếu thực thi nó theo cách thủ công từ dòng lệnh.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>

122
2017-09-22 15:20



Sử dụng cách tiếp cận trong câu trả lời này dẫn đến thông báo lỗi sau: 'Không thể tải thuộc tính tệp kê khai chính từ tệp <jar>' khi cố gắng chạy tệp JAR bằng 'java -jar <jar file>' - Elmo
Phần lưu trữ của maven-jar-plugin là cần thiết <archive> <manifest> <addClasspath> true </ addClasspath> <mainClass> fully.qualified.MainClass </ mainClass> </ manifest> </ archive> - RockyMM
Rất tiếc, câu trả lời này là sai, thẻ mainClass phải nằm trong mục nhập maven-assembly-plugin vì bạn đang gọi trong mục tiêu gói - Alex Lehmann
@AlexLehmann đúng! - RockyMM
Tôi ngạc nhiên, tại sao không thể pom.xml đã bao gồm điều này sau khi mvn archetype: generate command? Nó là loại gây phiền nhiễu để tự sao chép-dán này mỗi khi tôi tạo ra một dự án maven mới ... - wintermute


Sử dụng plugin maven-shade để đóng gói tất cả các phụ thuộc vào một uber-jar. Nó cũng có thể được sử dụng để xây dựng một jar thực thi bằng cách chỉ định lớp chính. Sau khi cố gắng sử dụng maven-assembly và maven-jar, tôi thấy rằng plugin này phù hợp nhất với nhu cầu của tôi.

Tôi thấy plugin này đặc biệt hữu ích vì nó kết hợp nội dung của các tệp cụ thể thay vì ghi đè chúng. Điều này là cần thiết khi có các tệp tài nguyên có cùng tên trên các jars và plugin cố gắng đóng gói tất cả các tệp tài nguyên

Xem ví dụ bên dưới

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>

91
2018-03-13 20:55



Vì vậy, làm thế nào để bcprov-jdk15.jar nhận được vào classpath trong thời gian chạy, cho rằng nó bị loại trừ khỏi quá trình tô bóng? - Andrew Swan
Nó đã bị kéo bởi cxf-rt-ws-security, một phần phụ thuộc của tôi - Vijay Katam
Chưa bao giờ nghe nói về plugin này trước đây, nhưng nó đã giải quyết được vấn đề của tôi với spring.handlers bên trong các lọ. Cảm ơn! - Alexandre L Telles
Những người có ngoại lệ bảo mật, loại trừ DSA khỏi Manifest. Kiểm tra maven.apache.org/plugins/maven-shade-plugin/examples/… - ruhsuzbaykus
+1 Tôi đã sử dụng minijar: ueberjar trong quá khứ, nhưng plugin minijar hiện không còn được dùng nữa và được thay thế bằng bóng râm - rds


Long đã sử dụng plugin lắp ráp mavennhưng tôi không thể tìm ra giải pháp cho vấn đề "already added, skipping". Bây giờ, tôi đang sử dụng một plugin khác - plugin onejar-maven. Ví dụ bên dưới (mvn package xây dựng jar):

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Bạn cần thêm kho lưu trữ cho plugin đó:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>

15
2017-10-13 12:16



làm thế nào để thoát khỏi các tin nhắn thêm trong đầu ra? - Alexandr


Bạn có thể sử dụng maven-dependency-plugin, nhưng câu hỏi là làm thế nào để tạo ra một JAR thực thi. Để làm điều đó yêu cầu thay đổi sau đối với phản hồi của Matthew Franglen (btw, sử dụng plugin phụ thuộc mất nhiều thời gian để xây dựng khi bắt đầu từ một mục tiêu sạch):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

14
2018-03-11 15:12





Một tùy chọn khác nếu bạn thực sự muốn đóng gói lại các nội dung JAR khác bên trong JAR kết quả duy nhất của bạn là Trình cắm Maven Assembly. Nó unpacks và sau đó repacks tất cả mọi thứ vào một thư mục thông qua <unpack>true</unpack>. Sau đó, bạn sẽ có một vượt qua thứ hai mà xây dựng nó thành một JAR lớn.

Một tùy chọn khác là plugin OneJar. Điều này thực hiện các hành động đóng gói ở trên tất cả trong một bước.


13
2017-08-13 18:23





Bạn có thể thêm thông tin sau vào pom.xml:

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

Sau đó bạn phải chuyển qua giao diện điều khiển đến thư mục, nơi có tệp pom.xml. Sau đó, bạn phải thực thi mvn assembly: single và sau đó tệp JAR thực thi của bạn với các phụ thuộc sẽ được hy vọng xây dựng. Bạn có thể kiểm tra nó khi chuyển sang thư mục đầu ra (đích) với cd ./target và bắt đầu lọ của bạn với lệnh tương tự java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar.

Tôi đã thử nghiệm điều này với Apache Maven 3.0.3.


11
2017-11-26 14:17