Termasuk dependensi dalam toples dengan Maven


353

Apakah ada cara untuk memaksa maven (2.0.9) untuk memasukkan semua dependensi dalam satu file jar?

Saya punya proyek build menjadi file jar tunggal. Saya ingin kelas-kelas dari dependensi juga disalin ke dalam toples.

Pembaruan: Saya tahu bahwa saya tidak bisa hanya memasukkan file jar ke file jar. Saya mencari cara untuk membongkar guci yang ditentukan sebagai dependensi, dan mengemas file kelas ke dalam toples saya.




2
Bagaimana cara memasukkan file jar ke file jar di maven?
Kush Patel

Jawaban:


488

Anda dapat melakukan ini menggunakan plugin maven-assembly dengan deskriptor "jar-dengan-dependensi". Berikut bagian yang relevan dari salah satu pom.xml kami yang melakukan ini:

  <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
The attachedTujuan sudah ditinggalkan. The singleatau directory-singletujuan harus lebih disukai sebagai gantinya.
Pascal Thivent

16
directory-singlesekarang sudah usang juga.
James McMahon

14
menggunakan single direkomendasikan di situs web
mateuszb

42
Jika ada orang mvn baru yang terjebak seperti saya, tambahkan plugin ke <plugins> di dalam <build> yang ada di dalam <project>.
DA

10
@ Christian.tucker Ada jar ke-2 di direktori target yang dibuat seperti ini: ./target/example-0.0.1-SNAPSHOT.jar dan ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
technocrat

145

Dengan Maven 2, cara yang tepat untuk melakukan ini adalah dengan menggunakan Plugin Majelis Maven2 yang memiliki file deskriptor yang telah ditentukan sebelumnya untuk tujuan ini dan yang bisa Anda gunakan pada baris perintah:

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

Jika Anda ingin membuat toples ini dapat dieksekusi, cukup tambahkan kelas utama untuk dijalankan ke konfigurasi 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>

Jika Anda ingin membuat perakitan itu sebagai bagian dari proses pembuatan normal, Anda harus mengikat tujuan tunggal atau direktori-tunggal ( assemblytujuan HANYA harus dijalankan dari baris perintah) ke fase siklus hidup ( packagemasuk akal), sesuatu seperti ini:

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

Adaptasi configurationelemen yang sesuai dengan kebutuhan Anda (misalnya dengan hal-hal nyata seperti yang diucapkan).


Saya mencoba persis ini, namun plugin tidak berjalan dan file jar tidak dibuat meskipun build dijalankan dengan lancar. Apakah ada perangkap umum yang mungkin membuat saya terjebak?
posdef

6
Ini bekerja untuk saya tetapi memiliki pencarian. setelah membangun sekarang dua toples dibuat satu dengan versi proyek artifactid dan yang lain dengan versi artifactid- "jar-dengan-dependensi". Tapi saya ingin hanya satu toples yang dibuat. Apakah ada cara lain
Souvik Bhattacharya

38

Jika Anda ingin melakukan file jar yang dapat dieksekusi, mereka perlu mengatur kelas utama juga. Jadi konfigurasi penuh seharusnya.

    <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
Mengapa nama toples ditambahkan dengan "toples-dengan-dependensi" ?! Ada solusi?
Tina J

1
@Tina J Anda dapat menambahkan <appendAssemblyId>false</appendAssemblyId>di dalam <configuration>tag untuk mengecualikan akhiran "-jar-with-dependencies" di nama akhir.
ccu


17

Anda dapat menggunakan tabung yang baru dibuat menggunakan <classifier>tag.

<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

Jika Anda (seperti saya) tidak begitu menyukai pendekatan toples-dengan-dependensi yang dijelaskan di atas, solusi pakar yang saya sukai adalah dengan hanya membangun proyek-WAR, bahkan jika itu hanya aplikasi java yang berdiri sendiri yang sedang Anda bangun:

  1. Buat proyek jar biasa, yang akan membangun file jar Anda (tanpa dependensi).

  2. Juga, atur proyek perang maven (dengan hanya file src / main / webapp / WEB-INF / web.xml kosong , yang akan menghindari peringatan / kesalahan dalam pembuatan maven), yang hanya memiliki proyek jar Anda sebagai ketergantungan, dan jadikan proyek jar Anda sebagai proyek <module>perang Anda. (Proyek perang ini hanya trik sederhana untuk membungkus semua dependensi file jar Anda menjadi file zip.)

  3. Bangun proyek perang untuk menghasilkan file perang.

  4. Pada langkah penyebaran, cukup ganti nama file .war Anda menjadi * .zip dan unzip.

Anda sekarang harus memiliki direktori-lib (yang bisa Anda pindahkan ke tempat yang Anda inginkan) dengan toples Anda dan semua dependensi yang Anda perlukan untuk menjalankan aplikasi Anda:

java -cp 'path/lib/*' MainClass

(Wildcard di classpath berfungsi di Java-6 atau lebih tinggi)

Saya pikir ini lebih mudah untuk setup di maven (tidak perlu dipusingkan dengan plugin assembly) dan juga memberi Anda pandangan yang lebih jelas tentang struktur-aplikasi (Anda akan melihat nomor versi semua guci yang tergantung dalam tampilan biasa, dan hindari menyumbat semuanya menjadi satu file jar).


Apakah sama dengan Eclipse "Export as Runnable jar"? Karena dengan ini Anda dapat memilih untuk "mengemas semua dependensi dengan JAR", Anda kemudian mendapatkan semua dependensi dalam folder project-lib, di sepanjang toples Anda.
WesternGun

@ FaithReaper - Mungkin "sama", saya tidak pernah mencobanya. Tapi saya kira jika Anda menggunakan Eclipse, itu tidak mudah skrip, yang merupakan persyaratan, jika Anda ingin menerapkan membangun otomatis + deploy-pipeline. Sebagai contoh, biarkan Jenkins-server melakukan build dari repositori git Anda, atau yang serupa.
Rop

12

http://fiji.sc/Uber-JAR memberikan penjelasan yang sangat baik tentang alternatif:

Ada tiga metode umum untuk membangun uber-JAR:

  1. Tidak berbayang. Buka kemasan semua file JAR, lalu bungkus kembali menjadi satu JAR.
    • Pro: Bekerja dengan loader kelas default Java.
    • Con: File hadir dalam beberapa file JAR dengan jalur yang sama (misalnya, META-INF / services / javax.script.ScriptEngineFactory) akan menimpa satu sama lain, mengakibatkan perilaku yang salah.
    • Alat: Plugin Majelis Maven, Classworlds Uberjar
  2. Diarsir. Sama seperti tidak berbayang, tetapi ganti nama (yaitu, "teduh") semua paket semua dependensi.
    • Pro: Bekerja dengan loader kelas default Java. Menghindari beberapa benturan versi ketergantungan (tidak semua).
    • Con: File hadir dalam beberapa file JAR dengan jalur yang sama (misalnya, META-INF / services / javax.script.ScriptEngineFactory) akan menimpa satu sama lain, mengakibatkan perilaku yang salah.
    • Alat: Plugin Maven Shade
  3. JAR JAR. File JAR terakhir berisi file JAR lain yang tertanam di dalamnya.
    • Pro: Menghindari bentrokan versi ketergantungan. Semua file sumber daya dipertahankan.
    • Con: Perlu bundel classloader "bootstrap" khusus untuk memungkinkan Java memuat kelas dari file JAR yang dibungkus. Masalah pemuatan kelas debugging menjadi lebih kompleks.
    • Alat: Pengekspor File JAR Eclipse, One-JAR.

1
Tidak sepenuhnya benar mengenai layanan, naungan plugin memiliki transformer dan salah satunya adalah untuk menyatukan konten file di bawah META-INF/servicesdirektori. Info lebih lanjut di sini: 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

Solusi definitif saya tentang Eclipse Luna dan m2eclipse: Custom Classloader (unduh dan tambahkan ke proyek Anda, hanya 5 kelas): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; classloader ini adalah yang terbaik dari classloader satu jar dan sangat cepat;

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

Sunting di JIJConstants "Rsrc-Class-Path" ke "Class-Path"
mvn bersih dependensi: paket dependensi-salinan
dibuat jar dengan dependensi dalam folder lib dengan classloader tipis

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

the maven-dependency-plugin <outputDirectory> tidak berfungsi, selalu tulis di folder "dependency"
Glaucio Southier

buat toples dengan "dependensi" folder internal yang berisi dependensi proyek dan letakkan di MANIFEST.MF
Glaucio Southier

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

1
Berdasarkan jawaban ini saya membuat proyek ini. Anda tidak perlu mengubah apa pun kecuali file pom: github.com/raisercostin/jarinjarloader
raisercostin


0

Posting ini mungkin agak lama, tetapi saya juga punya masalah yang sama baru-baru ini. Solusi pertama yang diusulkan oleh John Stauffer adalah solusi yang bagus, tetapi saya memiliki beberapa masalah saat saya bekerja pada musim semi ini. Stoples dependensi pegas yang saya gunakan memiliki beberapa file properti dan deklarasi xml-schemas yang berbagi jalur dan nama yang sama. Meskipun guci ini berasal dari versi yang sama, guci-dengan-dependensi tujuan maven adalah menimpa file tesis dengan file terakhir yang ditemukan.

Pada akhirnya, aplikasi tidak dapat memulai karena guci spring tidak dapat menemukan file properti yang benar. Dalam hal ini solusi yang diajukan oleh Rop telah memecahkan masalah saya.

Juga sejak itu, proyek spring-boot sekarang ada. Ini memiliki cara yang sangat keren untuk mengelola masalah ini dengan menyediakan tujuan pakar yang membebani tujuan paket dan menyediakan pemuat kelasnya sendiri. Lihat Panduan Referensi pegas-boot


0

Lihatlah jawaban ini:

Saya membuat penginstal yang dijalankan sebagai file Java JAR dan perlu membongkar file WAR dan JAR ke tempat yang sesuai di direktori instalasi. Plugin dependensi dapat digunakan dalam fase paket dengan tujuan salin dan itu akan mengunduh file apa pun di repositori Maven (termasuk file WAR) dan menuliskannya di mana pun Anda membutuhkannya. Saya mengubah direktori output ke $ {project.build.directory} / kelas dan kemudian hasil akhirnya adalah bahwa tugas JAR normal termasuk file saya baik-baik saja. Saya kemudian dapat mengekstraknya dan menuliskannya ke direktori instalasi.

<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

Terima kasih, saya telah menambahkan potongan di bawah ini dalam file POM.xml dan masalah Mp diselesaikan dan membuat file jar lemak yang mencakup semua stoples bergantung.

<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>
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.