Bao gồm các phụ thuộc trong một cái lọ với Maven


353

Có cách nào để buộc maven (2.0.9) bao gồm tất cả các phụ thuộc trong một tệp jar không?

Tôi có một dự án xây dựng thành một tệp jar duy nhất. Tôi muốn các lớp từ phụ thuộc cũng được sao chép vào jar.

Cập nhật: Tôi biết rằng tôi không thể chỉ bao gồm một tệp jar trong một tệp jar. Tôi đang tìm cách để giải nén các lọ được chỉ định là phụ thuộc và đóng gói các tệp lớp vào bình của tôi.




2
Làm cách nào để đưa tệp jar vào tệp jar trong maven?
Kush Patel

Câu trả lời:


488

Bạn có thể thực hiện việc này bằng cách sử dụng plugin maven-lắp ráp với bộ mô tả "jar-with-Depencies". Đây là đoạn liên quan từ một trong những tệp pom.xml của chúng tôi thực hiện điều này:

  <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
Các attachedmục tiêu bị phản đối. Các singlehoặc directory-singlemục tiêu nên được ưa thích để thay thế.
Pascal Thivent

16
directory-singlebây giờ cũng bị phản đối
James McMahon

14
sử dụng đĩa đơn được khuyến nghị trên trang web
mateuszb

42
Trong trường hợp bất kỳ người mvn mới nào bị mắc kẹt như tôi, hãy thêm plugin vào <plugin> bên trong <build> bên trong <project>.
DA

10
@ Christian.tucker Có một jar thứ 2 trong thư mục đích được tạo như thế này: ./target/example-0.0.1-SNAPSHOT.jar./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
kỹ thuật viên

145

Với Maven 2, cách đúng đắn để làm điều này là sử dụng Plugin Maven2 hộitệp mô tả được xác định trước cho mục đích này và bạn chỉ có thể sử dụng trên dòng lệnh:

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

Nếu bạn muốn làm cho tệp jar này có thể thực thi được, chỉ cần thêm lớp chính sẽ được chạy vào cấu hình plugin:

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

Nếu bạn muốn tạo tập hợp đó như là một phần của quy trình xây dựng thông thường, bạn nên liên kết mục tiêu đơn hoặc thư mục ( assemblymục tiêu CHỈ nên được chạy từ dòng lệnh) sang giai đoạn vòng đời ( packagecó ý nghĩa), đại loại như sau:

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

Điều chỉnh configurationyếu tố cho phù hợp với nhu cầu của bạn (ví dụ với nội dung rõ ràng như đã nói).


Tôi đang thử chính xác điều này, tuy nhiên plugin không chạy và tệp jar không được tạo mặc dù bản dựng thực thi trơn tru. Có một cạm bẫy phổ biến mà tôi có thể đã bị mắc kẹt?
posdef

6
Nó làm việc cho tôi nhưng có một nhiệm vụ. sau khi xây dựng, hai cái lọ được tạo ra với một phiên bản artifactid và một cái khác có phiên bản artifactid - "jar-with-Depencies". Nhưng tôi muốn chỉ có một bình được xây dựng. Có cách nào khác không
Souvik Bhattacharya

38

Nếu bạn muốn làm một tệp jar thực thi, chúng cũng cần đặt lớp chính. Vì vậy, cấu hình đầy đủ nên được.

    <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
Tại sao tên của jar được thêm vào bởi "jar-with-Depencies"?! Bất kỳ cách giải quyết?
Tina J

1
@Tina J bạn có thể thêm <appendAssemblyId>false</appendAssemblyId>vào bên trong <configuration>thẻ để loại trừ hậu tố "-jar-with- Depencies " trong tên cuối cùng.
ccu


17

Bạn có thể sử dụng bình vừa tạo bằng <classifier>thẻ.

<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

Nếu bạn (như tôi) không đặc biệt thích cách tiếp cận phụ thuộc jar được mô tả ở trên, thì giải pháp maven tôi thích chỉ đơn giản là xây dựng một dự án WAR, ngay cả khi đó chỉ là một ứng dụng java độc lập mà bạn đang xây dựng:

  1. Tạo một dự án jar maven bình thường, nó sẽ xây dựng tệp jar của bạn (không có phụ thuộc).

  2. Ngoài ra, hãy thiết lập dự án chiến tranh maven (chỉ với tệp src / main / webapp / WEB-INF / web.xml trống , sẽ tránh cảnh báo / lỗi trong bản dựng maven), chỉ có dự án jar của bạn như một sự phụ thuộc và làm cho dự án jar của bạn trở thành một dự án <module>chiến tranh của bạn. (Dự án chiến tranh này chỉ là một mẹo đơn giản để bọc tất cả các phụ thuộc tệp jar của bạn vào một tệp zip.)

  3. Xây dựng dự án chiến tranh để sản xuất tập tin chiến tranh.

  4. Trong bước triển khai, chỉ cần đổi tên tệp .war của bạn thành * .zip và giải nén nó.

Bây giờ bạn sẽ có một thư mục lib (mà bạn có thể di chuyển đến nơi bạn muốn) với jar của bạn và tất cả các phụ thuộc bạn cần để chạy ứng dụng của bạn:

java -cp 'path/lib/*' MainClass

(Ký tự đại diện trong classpath hoạt động trong Java-6 trở lên)

Tôi nghĩ rằng điều này vừa đơn giản hơn để thiết lập trong maven (không cần phải loay hoay với plugin lắp ráp) và cũng cho bạn cái nhìn rõ hơn về cấu trúc ứng dụng (bạn sẽ thấy số phiên bản của tất cả các lọ phụ thuộc trong chế độ xem đơn giản và tránh làm tắc nghẽn mọi thứ vào một tệp jar duy nhất).


Có giống như Eclipse "Xuất dưới dạng bình chạy" không? Bởi vì với điều này, bạn có thể chọn "đóng gói tất cả các phụ thuộc với JAR", sau đó bạn nhận được tất cả các phụ thuộc trong thư mục dự án-lib, cùng với jar của bạn.
WesternGun

@FaithReaper - Có thể là "giống nhau", tôi chưa bao giờ thử điều đó. Nhưng tôi đoán nếu bạn sử dụng Eclipse, nó không phải là kịch bản dễ dàng, đó là một yêu cầu, nếu bạn muốn triển khai một đường dẫn xây dựng + triển khai tự động . Ví dụ: hãy để Jenkins-server thực hiện việc xây dựng từ kho lưu trữ nguồn git của bạn hoặc tương tự.
Rop

12

http://fiji.sc/Uber-JAR cung cấp một lời giải thích tuyệt vời về các lựa chọn thay thế:

Có ba phương pháp phổ biến để xây dựng một uber-JAR:

  1. Không che chắn. Giải nén tất cả các tệp JAR, sau đó đóng gói lại thành một tệp JAR duy nhất.
    • Pro: Hoạt động với trình nạp lớp mặc định của Java.
    • Con: Các tệp có trong nhiều tệp JAR có cùng đường dẫn (ví dụ: META-INF / services / javax.script.ScriptEngineFactory) sẽ ghi đè lên nhau, dẫn đến hành vi bị lỗi.
    • Công cụ: Plugin Maven hội, Classworlds Uberjar
  2. Bóng mờ. Tương tự như không bóng, nhưng đổi tên (nghĩa là "bóng râm") tất cả các gói của tất cả các phụ thuộc.
    • Pro: Hoạt động với trình nạp lớp mặc định của Java. Tránh một số (không phải tất cả) xung đột phiên bản phụ thuộc.
    • Con: Các tệp có trong nhiều tệp JAR có cùng đường dẫn (ví dụ: META-INF / services / javax.script.ScriptEngineFactory) sẽ ghi đè lên nhau, dẫn đến hành vi bị lỗi.
    • Công cụ: Plugin Maven Shadow
  3. JAR của JAR. Tệp JAR cuối cùng chứa các tệp JAR khác được nhúng bên trong.
    • Pro: Tránh đụng độ phiên bản phụ thuộc. Tất cả các tệp tài nguyên được bảo tồn.
    • Con: Cần gói một trình nạp lớp "bootstrap" đặc biệt để cho phép Java tải các lớp từ các tệp JAR được gói. Gỡ lỗi các vấn đề trình nạp lớp trở nên phức tạp hơn.
    • Công cụ: Trình xuất tệp JAR của Eclipse, One-JAR.

1
Không hoàn toàn đúng về các dịch vụ, plugin bóng râm có máy biến áp và một trong số đó là để nối các nội dung của các tệp trong META-INF/servicesthư mục. Thêm thông tin ở đây: maven.apache.org/plugins/maven-shade-plugin/examples/ khác
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

Giải pháp dứt khoát của tôi về Eclipse Luna và m2eclipse: Trình tải lớp tùy chỉnh (tải xuống và thêm vào dự án của bạn, chỉ 5 lớp): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / Internal / jarinjarloader / ; trình nạp lớp này là tốt nhất của trình nạp lớp một bình và rất nhanh;

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

Chỉnh sửa trong JIJConstants "Rsrc-Class-Path" thành "Class-Path"
mvn phụ thuộc sạch: gói phụ thuộc sao chép
được tạo một tệp có phụ thuộc trong thư mục lib với trình nạp lớp mỏng

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

plugin phụ thuộc maven <outputDirectory> không hoạt động, luôn luôn ghi vào thư mục "phụ thuộc"
Glaucio Southier

tạo một cái bình với một thư mục nội bộ "phụ thuộc" chứa các phụ thuộc của dự án và đặt nó vào MANIFEST.MF
Glaucio Southier

<resource> <resource> <thư mục> src / main / java </ thư mục> <bao gồm> <bao gồm> ** / *. java </ include> <bao gồm> ** / *. thuộc tính </ include> </ gồm > </ resource> <resource> <thư mục> src / main / resource </ thư mục> <lọc> đúng </ lọc> <bao gồm> <bao gồm> ** / * </ bao gồm> </ bao gồm> <targetPath> META -INF / </ targetPath> </ resource> <resource> <thư mục> $ {project.build.directory} / lệ thuộc / </ thư mục> <bao gồm> <bao gồm> *. Jar </ include> </ gồm> < targetPath> lib / </ targetPath> </ resource> </ resource>
Glaucio Southier

1
Dựa trên câu trả lời này tôi đã tạo ra dự án này. Bạn không cần thay đổi bất cứ điều gì ngoại trừ tệp pom: github.com/raisercostin/jarinjarloader
raisercostin


0

Bài đăng này có thể hơi cũ, nhưng tôi cũng gặp vấn đề tương tự gần đây. Giải pháp đầu tiên được đề xuất bởi John Stauffer là một giải pháp tốt, nhưng tôi đã gặp một số vấn đề khi tôi làm việc vào mùa xuân này. Các lọ phụ thuộc của lò xo mà tôi sử dụng có một số tệp thuộc tính và khai báo xml-lược đồ có chung đường dẫn và tên. Mặc dù những chiếc lọ này đến từ cùng một phiên bản, nhưng chiếc lọ có phụ thuộc mục tiêu maven- đã ghi đè lên tệp luận văn với tệp cuối cùng được tìm thấy.

Cuối cùng, ứng dụng không thể khởi động vì các lọ lò xo không thể tìm thấy các tệp thuộc tính chính xác. Trong trường hợp này, giải pháp được đề xuất bởi Rop đã giải quyết vấn đề của tôi.

Cũng kể từ đó, dự án khởi động mùa xuân bây giờ tồn tại. Nó có một cách rất hay để quản lý vấn đề này bằng cách cung cấp một mục tiêu maven làm quá tải mục tiêu gói và cung cấp trình nạp lớp riêng của nó. Xem Hướng dẫn tham khảo giày lò xo


0

Hãy xem câu trả lời này:

Tôi đang tạo một trình cài đặt chạy dưới dạng tệp Java JAR và nó cần giải nén các tệp WAR và JAR vào các vị trí thích hợp trong thư mục cài đặt. Plugin phụ thuộc có thể được sử dụng trong giai đoạn gói với mục tiêu sao chép và nó sẽ tải xuống bất kỳ tệp nào trong kho lưu trữ Maven (bao gồm các tệp WAR) và viết chúng bất cứ khi nào bạn cần. Tôi đã thay đổi thư mục đầu ra thành $ {project.build.directory} / class và kết quả cuối cùng là tác vụ JAR bình thường bao gồm các tệp của tôi tốt. Sau đó tôi có thể giải nén chúng và ghi chúng vào thư mục cài đặt.

<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

Cảm ơn tôi đã thêm đoạn mã bên dưới vào tệp POM.xml và sự cố Mp đã được giải quyết và tạo tệp jar chất béo bao gồm tất cả các tệp phụ thuộc.

<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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.