Pytanie Jak mogę utworzyć plik wykonywalny JAR z zależnościami za pomocą Mavena?


Chcę spakować mój projekt w pojedynczym wykonywalnym pliku JAR do dystrybucji.

Jak mogę uczynić pakiet projektu Maven wszystkimi JAR zależnościami w moim pliku wyjściowym JAR?


1944
2018-02-22 08:43


pochodzenie


Wyjaśnij, do którego celu odnosi się wtyczka zależności. Nie znam żadnego celu, który spełnia to, o co prosi oryginalne pytanie: umieścić wszystkie zależności: A) wewnątrz słoju autora przez przepakowanie, lub B) utworzyć plik wykonywalny, który ma pozostałe pliki w ścieżce klasy MANIFEST.MF - Matthew McCullough
Może się to okazać przydatne rationaljava.com/2015/02/... - Dan
2 przykłady: tugay.biz/2015/12/a-standalone-java-web-application-with.html  tugay.biz/2016/11/how-did-i-create-exable-jar-with.html - Koray Tugay
Odnosić się stackoverflow.com/questions/35217128/... - Thanga


Odpowiedzi:


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

i uruchamiasz go

mvn clean compile assembly:single

Cel kompilacji powinien zostać dodany przed montażem: pojedynczy lub w inny sposób, kod w twoim projekcie nie został uwzględniony.

Zobacz więcej szczegółów w komentarzach.


Zwykle ten cel jest powiązany z fazą kompilacji, aby wykonać ją automatycznie. Gwarantuje to zbudowanie JAR podczas wykonywania mvn install lub wykonanie wdrożenia / wydania.

<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



Dzięki @IAdapter. Zauważ, że zawsze powinieneś zrobić kompilację przed rozdaniem, ponieważ po prostu umieści to, co jest w "docelowym / klasach" w JAR. Zapewni to, że JAR zawiera wszelkie zmiany, które ostatnio wprowadziłeś do kodu źródłowego. Powinieneś więc zrobić coś takiego: mvn clean compile assembly:single. - Michael
Zmieniłem to pytanie, aby uwzględnić powiązanie fazowe. Usunąłem przestarzały cel montażu, ponieważ nikt nie musi o tym wiedzieć. - Duncan Jones
Widzę, że to nie dodaje słoików do słoika uber, zamiast tego po prostu dodaje wszystkie pliki klas do słoika. - pitchblack408
Wskazówka: możesz także dodać element <appendAssemblyId>false</appendAssemblyId> do configuration aby uniknąć denerwującego przyrostka "-jar-z-zależnościami" w nazwie - maxivis
zapomnieć compile i jesteś spieprzony. - prayagupd


Za pomocą pluginów zależności można wygenerować wszystkie zależności w oddzielnym katalogu przed fazą pakietu, a następnie uwzględnić ją w ścieżce klasy manifestu:

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

Alternatywnie użyj ${project.build.directory}/classes/lib jako OutputDirectory, aby zintegrować wszystkie pliki jar w głównym słoiku, ale wtedy będziesz musiał dodać niestandardowy kod ładujący klasy, aby załadować słoiki.


294
2018-06-02 03:01



+1 Doskonały. Powodem, dla którego używam wtyczki zależnej od mavenów, a nie wtyczką typu maven-assembly jest to, że używam również wtyczki buildnumber-maven i w ten sposób mogę przechowywać numer wersji w manifeście każdego słoja z osobna. - PapaFreud
Podoba mi się Twoje rozwiązanie. używam ${project.build.directory}/classes/lib tak jak outputDirectory mieć jeden główny plik .jar ze wszystkimi zależnościami wewnątrz, ale - jak dodać niestandardowy kod ładujący klasy, aby załadować te słoiki? Muszę wykonać wykonanie pracy jak: java -jar main-jar-with-deps.jar. Czy to możliwe ? - marioosh
@ André Aronsen, użyłem tego rozwiązania, aby dodać zależności w folderze lib wewnątrz słoika, ale zawsze otrzymuję wyjątek klasy nie znaleziono, czy możesz doradzić, jak to naprawić. - Mahmoud Saleh
+1 do ciebie !! Wygląda na to, że dodatek maven-assembly "słoik-z-zależnościami" nie działa dobrze. Brakowało mi niektórych wpisów z META-INF / spring.schemas w wygenerowanym słoiku. Zniszczyłem więc słoik-zależności i użyłem twojego rozwiązania powyżej. Perfekcyjnie, dzięki!!! - Derek
Dla każdego, kto napotka na ten problem, musisz umieścić folder lib w tym samym katalogu, co twój jar, do którego przenosisz słoik. - Sparticles


Blogowałem o różnych sposobach na zrobienie tego.

Widzieć Wykonywany słoik z Apache Maven (WordPress)

lub executable-jar-with-maven-example (GitHub)

Uwagi

Te plusy i minusy są dostarczane przez Stephan.


Do ręcznego wdrażania

  • Plusy
  • Cons
    • Zależności są poza końcowym słojem.

Skopiuj zależności do określonego katalogu

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

Wykonaj plik wykonywalny słoika i Śledź Classpath

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

W tym momencie jar jest rzeczywiście wykonywalna z zewnętrznymi elementami klasy classpath.

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

Utwórz archiwa z możliwością rozmieszczania

The jar plik jest wykonywalny tylko z rodzeństwem ...lib/ informator. Musimy stworzyć archiwa do wdrożenia wraz z katalogiem i jego zawartością.

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

Teraz masz target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz) które każdy zawiera jar i lib/*.


Apache Maven Assembly Plugin

  • Plusy
  • Cons
    • Brak obsługi przenoszenia klasy (użyj wtyczki maven-shade-plug, jeśli wymagana jest relokacja klasy).
<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>

Ty masz target/${project.bulid.finalName}-jar-with-dependencies.jar.


Apache Maven Shade Plugin

  • Plusy
  • Cons
<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>

Ty masz target/${project.build.finalName}-shaded.jar.


onejar-maven-plugin

  • Plusy
  • Cons
    • Nieaktywnie wspierane od 2012 roku.
<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

  • Plusy
  • Cons
    • Dodaj potencjalne niepotrzebne klasy związane z wiosną i wiosną.
<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>

Ty masz target/${project.bulid.finalName}-spring-boot.jar.


134
2018-02-26 04:31



Jedyny, który pracuje dla mnie to ręczne wdrażanie. - caiohamamura
@caiohamamura Możesz sklonować Repozytorium GitHub i zobacz, jak działają wszystkie profile. - Jin Kwon
Problem dotyczył pakietu, którego używałem: stackoverflow.com/a/12622037/2548351 - caiohamamura


Biorąc odpowiedź Unanswered i zmieniając ją, mamy:

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

Następnie, polecam uczynienie tego naturalną częścią twojej kompilacji, a nie czymś, co można wyraźnie nazwać. Aby było to integralną częścią twojej kompilacji, dodaj tę wtyczkę do swojej pom.xml i związać go z package wydarzenie cyklu życia. Jednak jest to, że musisz zadzwonić do assembly:single cel, jeśli wstawisz to do swojego pom.xml, podczas gdy nazwałbyś "assembly: assembly", jeśli wykonywałeś to ręcznie z wiersza poleceń.

<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



Użycie podejścia w tej odpowiedzi powoduje wyświetlenie następującego komunikatu o błędzie: "Załadowanie pliku JAR przy użyciu" java -jar <plik jar> "nie powiodło się załadowanie atrybutu manifestu klasy głównej z <pliku jar> - Elmo
Wymagana jest część archiwalna wtyczki maven-jar <archive> <manifest> <addClasspath> true </ addClasspath> <mainClass> fully.qualified.MainClass </ mainClass> </ manifest> </ archive> - RockyMM
Niestety, ta odpowiedź jest całkiem błędna, znacznik mainClass musi znajdować się we wpisie pluginu maven-assembly, ponieważ wywołujesz go podczas realizacji celu pakietu - Alex Lehmann
@AlexLehmann prawda! - RockyMM
Jestem zaskoczony, dlaczego pom.xml nie może już zawierać tego po mvn archetype: generate command? Jest to dość denerwujące, aby ręcznie kopiować i wklejać je za każdym razem, gdy tworzę nowy projekt maven ... - wintermute


Użyj wtyczki maven-shade, aby spakować wszystkie zależności w jeden uber-jar. Można go również użyć do zbudowania pliku wykonywalnego, określając główną klasę. Po próbach użycia maven-assembly i maven-jar odkryłem, że ta wtyczka najlepiej odpowiada moim potrzebom.

Zauważyłem, że ta wtyczka jest szczególnie użyteczna, ponieważ łączy zawartość konkretnych plików zamiast ich nadpisywać. Jest to potrzebne, gdy istnieją pliki zasobów, które mają taką samą nazwę w słoikach, a wtyczka próbuje spakować wszystkie pliki zasobów

Zobacz przykład poniżej

      <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



W jaki sposób bcprov-jdk15.jar dostaje się do ścieżki klasy w czasie wykonywania, biorąc pod uwagę, że jest ona wyłączona z procesu cieniowania? - Andrew Swan
Został on ściągnięty przez cxf-rt-ws-security, który jest częścią moich zależności - Vijay Katam
Nigdy wcześniej nie słyszałem o tej wtyczce, ale rozwiązał mój problem z spring.handlers wewnątrz słoików. Dzięki! - Alexandre L Telles
Ci, którzy otrzymali wyjątek bezpieczeństwa, wykluczają DSA z Manifestu. Czek maven.apache.org/plugins/maven-shade-plugin/examples/... - ruhsuzbaykus
+1 Użyłem minijar: ueberjar w przeszłości, ale plugin minijar jest teraz przestarzały i zastąpiony cieniem - rds


Dawno używałeś maven assembly plugin, ale nie mogłem znaleźć rozwiązania tego problemu "already added, skipping". Teraz używam innej wtyczki - onejar-maven-plugin. Przykład poniżej (mvn package zbuduj słoik):

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

Musisz dodać repozytorium dla tej wtyczki:

<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



jak pozbyć się dodatkowych komunikatów na wyjściu? - Alexandr


Możesz użyć wtyczki zależnej od maven, ale pytanie brzmiało, jak utworzyć plik wykonywalny JAR. Aby to zrobić, wymagana jest następująca zmiana w odpowiedzi udzielonej przez Matthew Franglena (btw, używanie wtyczki zależności wymaga więcej czasu, aby zbudować ją, gdy zaczynasz od czystego celu):

<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





Inną opcją, jeśli naprawdę chcesz ponownie spakować zawartość innych JARów w pojedynczym wypadkowym JAR, jest Wtyczka Maven Assembly. Rozpakowuje, a następnie ponownie umieszcza wszystko w katalogu za pośrednictwem <unpack>true</unpack>. Wtedy miałbyś drugie przejście, które wbudowało go w jeden ogromny JAR.

Inną opcją jest wtyczka OneJar. Wykonuje powyższe czynności przepakowania wszystko w jednym kroku.


13
2017-08-13 18:23





Możesz dodać następujące elementy do swojego 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>

Następnie musisz przełączyć się przez konsolę do katalogu, w którym znajduje się plik pom.xml. Następnie musisz wykonać montaż mvn: pojedynczy a następnie plik wykonywalny JAR z zależnościami zostanie utworzony. Możesz to sprawdzić, przełączając się do katalogu wyjściowego (docelowego) za pomocą cd ./target i uruchomienie twojego słoika z poleceniem podobnym do java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar.

Testowałem to z Apache Maven 3.0.3.


11
2017-11-26 14:17