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

2396

Chcę spakować mój projekt do jednego pliku wykonywalnego JAR w celu dystrybucji.

Jak mogę utworzyć pakiet projektu Maven ze wszystkimi plikami JAR zależności w moim wyjściowym pliku JAR?

soemirno
źródło
14
Wyjaśnij, do którego celu wtyczki zależności się odwołujesz. Nie znam celu, który spełnia wymagania pierwotnego pytania: umieścić wszystkie zależności albo A) w słoju autorów poprzez przepakowanie, albo B) stworzyć plik wykonywalny, który ma inne w ścieżce klasycznej MANIFEST.MF
Matthew McCullough
2
Przydatny może być rationaljava.com/2015/02/…
Dan

Odpowiedzi:

2358
<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 to z

mvn clean compile assembly:single

Cel kompilacji powinien zostać dodany przed złożeniem: pojedynczy lub inny kod własnego projektu nie jest uwzględniony.

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


Zwykle ten cel jest powiązany z fazą kompilacji, aby wykonać się automatycznie. Zapewnia to zbudowanie mvn installpliku JAR podczas wykonywania lub wykonywania 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>
IAdapter
źródło
22
Dzięki @IAdapter. Zauważ, że zawsze powinieneś wykonać kompilację przed ręką, ponieważ po prostu umieści ona wszystko, co jest w „celu / klasach” w JAR. Zapewni to, że JAR będzie zawierał wszelkie zmiany, które ostatnio wprowadziłeś w kodzie źródłowym. Tak więc, należy zrobić coś takiego: mvn clean compile assembly:single.
Michael
10
Zredagowałem pytanie, aby uwzględnić wiązanie fazowe. Usunąłem przestarzały cel montażu, ponieważ nikt nie musi o tym wiedzieć.
Duncan Jones
2
Widzę, że to nie dodaje słoików do słoika Ubera, zamiast tego dodaje tylko wszystkie pliki klas do słoika.
pitchblack408
170
Wskazówka: możesz także dodać element <appendAssemblyId>false</appendAssemblyId>do, configurationaby uniknąć irytującego przyrostka „
-jar
6
zapomnij compilei jesteś pieprzony.
prayagupd
349

Wtyczki zależności można użyć do wygenerowania wszystkich zależności w osobnym katalogu przed fazą pakietu, a następnie włączenia jej do ścieżki klas 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/libjako OutputDirectory do zintegrowania wszystkich plików jar w głównym jar, ale wtedy będziesz musiał dodać niestandardowy kod ładowania klas, aby załadować jar.

André Aronsen
źródło
3
+1 doskonale. Powodem, dla którego wybieram wtyczkę maven-zależność zamiast maven-a-plugin, jest to, że używam też wtyczki buildnumber-maven-plugin i w ten sposób mogę przechowywać numer wersji w manifeście każdego słoika osobno.
PapaFreud,
17
Lubię twoje rozwiązanie. Używam ${project.build.directory}/classes/libjako outputDirectorygłównego pliku .jar ze wszystkimi zależnościami, ale - jak dodać niestandardowy kod ładujący klasy, aby załadować te słoiki? Muszę zrobić wykonywania prac takich jak: java -jar main-jar-with-deps.jar. Czy to możliwe ?
marioosh
3
@ 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 nie znaleziony dla klasy, czy możesz doradzić, jak to naprawić.
Mahmoud Saleh
11
+1 dla ciebie !! Wygląda na to, że plugin montażowy maven „jar-with-dependencies” nie działa naprawdę dobrze. Brakowało niektórych wpisów z META-INF / spring.schemas w wygenerowanym słoju. Więc złomowałem słoik z zależnościami i użyłem twojego rozwiązania powyżej. Perfekcyjnie, dzięki!!!
Derek,
9
Dla każdego, kto napotka ten problem, musisz dołączyć folder lib do tego samego katalogu ze słoikiem, do którego dokądkolwiek go transportujesz.
Sparticles
224

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

Zobacz słój wykonywalny z Apache Maven (WordPress)

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

Notatki

Te zalety i wady zapewnia Stephan .


Do ręcznego wdrażania

  • Plusy
  • Cons
    • Zależności są poza ostatecznym słoikiem.

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>

Spraw, aby jar był wykonywalny, a Classpath świadomy

<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 jarjest to możliwe do wykonania z zewnętrznymi elementami ścieżki klasy.

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

Twórz archiwa do wdrożenia

jarPlik jest wykonywalny tylko z rodzeństwem ...lib/katalogu. Musimy stworzyć archiwa do wdrożenia 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óry zawiera jari lib/*.


Wtyczka Apache Maven Assembly

  • Plusy
  • Cons
    • Brak obsługi przeniesienia klasy (użyj wtyczki maven-shadow-plugin, jeśli przeniesienie klasy jest potrzebne).
<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>

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


Wtyczka Apache Maven Shade

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

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


wtyczka onejar-maven

  • Plusy
  • Cons
    • Nie aktywnie wspierany 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>

Wtyczka Spring Boot Maven

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

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

Jin Kwon
źródło
2
@caiohamamura Możesz sklonować repozytorium GitHub i zobaczyć, jak działają wszystkie profile.
Jin Kwon,
Problem polegał na tym, że
używałem
1
Myślę, że jest to prawdopodobnie najbardziej kompletna odpowiedź na ten temat.
Petr Bodnár
139

Biorąc odpowiedź bez odpowiedzi i ponownie ją formatując, 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 zaleciłbym uczynienie z tego naturalnej części twojej kompilacji, a nie czegoś, co można nazwać jawnie. Aby uczynić to integralną częścią twojej kompilacji, dodaj tę wtyczkę do swojej pom.xmli powiąż ją ze packagezdarzeniem cyklu życia. Jednak gotcha polega na tym, że musisz wywołać assembly:singlecel, jeśli umieścisz to w pliku pom.xml, a nazwałbyś „assembly: assembly”, jeśli wykonasz 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>
Matthew McCullough
źródło
10
Zastosowanie podejścia w tej odpowiedzi powoduje wyświetlenie następującego komunikatu o błędzie: „Nie udało się załadować atrybutu manifestu klasy głównej z <pliku jar>” podczas próby uruchomienia pliku JAR za pomocą polecenia „java -jar <plik jar>”
Elmo
3
Potrzebna jest część archiwalna wtyczki maven-jar-plug-in <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> full.qualified.MainClass </mainClass> </manifest> </archive>
Rade_303
4
Niestety, ta odpowiedź jest błędna, tag mainClass musi znajdować się we wpisie maven-assembly-plugin, ponieważ wywołujesz go podczas celu pakietu
Alex Lehmann
Dziwi mnie, dlaczego pom.xml nie może już zawierać tego po komendzie mvn archetype: generować? To trochę denerwujące, aby ręcznie skopiować i wkleić to za każdym razem, gdy tworzę nowy projekt maven ...
Wintermute
w pewnym sensie nie mam głównej metody ani klasy, po prostu mam klasę z funkcją. jak mogę zrobić słoik i go użyć
par
97

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

Uważam tę wtyczkę za szczególnie przydatną, ponieważ łączy ona zawartość określonych plików zamiast nadpisywać je. Jest to potrzebne, gdy istnieją pliki zasobów o tej samej nazwie 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>
Vijay Katam
źródło
Jak więc plik bcprov-jdk15.jar dostaje się do ścieżki klasy w czasie wykonywania, biorąc pod uwagę, że jest on wyłączony z procesu cieniowania?
Andrew Swan,
Został wciągnięty przez cxf-rt-ws-security, co jest częścią moich zależności
Vijay Katam
Nigdy wcześniej nie słyszałem o tej wtyczce, ale rozwiązało to mój problem z uchwytami Spring.handler wewnątrz słoików. Dzięki!
Alexandre L Telles
11
Ci, którzy dostali wyjątek bezpieczeństwa, wykluczają DSA z Manifestu. Sprawdź maven.apache.org/plugins/maven-shade-plugin/examples/…
ruhsuzbaykus
+1 W przeszłości korzystałem z minijar: ueberjar, ale wtyczka minijar jest teraz przestarzała i zastąpiona przez cień
rds
19

Dawno używałem wtyczki maven , ale nie mogłem znaleźć rozwiązania problemu "already added, skipping". Teraz używam innej wtyczki - onejar-maven-plugin . Przykład poniżej ( mvn packagebuild 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>

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>
marioosh
źródło
jak pozbyć się dodatkowych komunikatów na wyjściu?
Alexandr
17

Możesz użyć wtyczki maven-dependence, ale pytanie brzmiało, jak utworzyć wykonywalny plik JAR. Aby to zrobić, wymagana jest następująca modyfikacja odpowiedzi Matthew Franglena (przy okazji, użycie wtyczki zależności trwa dłużej, gdy zaczyna się 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>

źródło
16

Możesz użyć wtyczki maven-shadow, aby zbudować słoik Uber, jak poniżej

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Minisha
źródło
Ale w jaki sposób zostanie to zastosowane do repozytorium?
Francesco Gualazzi
15

Inną opcją, jeśli naprawdę chcesz przepakować inne pliki JAR w jednym wynikowym pliku JAR, jest wtyczka Maven Assembly . Rozpakowuje, a następnie przepakowuje wszystko do katalogu przez <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 przepakowywania w jednym kroku.

Matthew McCullough
źródło
14

Do pliku pom.xml możesz dodać następujące elementy :

<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 przejść 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 skompilowany. Możesz to sprawdzić, przechodząc do katalogu wyjściowego (docelowego) za pomocą cd ./target i uruchamiając jar za pomocą polecenia podobnego do java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

Testowałem to z Apache Maven 3.0.3 .

Benny Neugebauer
źródło
13

Przeanalizowałem każdą z tych odpowiedzi, szukając tłustego pliku wykonywalnego zawierającego wszystkie zależności i żadna z nich nie działała poprawnie. Odpowiedzią jest wtyczka cieniująca, która jest bardzo łatwa i bezpośrednia.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <executions>
         <!-- Run shade goal on package phase -->
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
             <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>path.to.MainClass</mainClass>
             </transformer>
          </transformers>
        </configuration>
          </execution>
      </executions>
    </plugin>

Pamiętaj, że aby zależności działały poprawnie, musisz mieć zakres kompilacji lub środowiska wykonawczego.

Ten przykład pochodzi z mkyong.com

dsutherland
źródło
Gdy to naprawię, czy mógłbyś zaktualizować swoją recenzję? Nie wziąłem pod uwagę twoich myśli przed opublikowaniem i szybko
poprawiłem
2
pluginElementem idzie w pom.xmlniedostatecznie build/plugins.
isapir
12

Możesz połączyć maven-shade-plugini maven-jar-plugin.

  • The maven-shade-pluginPakuje swoje zajęcia i wszystkie zależności w jednym pliku jar.
  • Skonfiguruj, maven-jar-pluginaby określał główną klasę pliku wykonywalnego jar (zobacz Konfigurowanie ścieżki klasy , rozdział „Tworzenie pliku jar ”).

Przykładowa konfiguracja POM dla maven-jar-plugin:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Na koniec utwórz plik wykonywalny jar, wywołując:

mvn clean package shade:shade
Oliver
źródło
3
Wtyczka Shade umożliwia teraz określenie pozycji klasy głównej w manifeście: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick
9

Moim zdaniem Ken Liu ma rację. Wtyczka zależności maven pozwala rozszerzyć wszystkie zależności, które można następnie traktować jako zasoby. Pozwala to na włączenie ich do głównego artefaktu. Użycie wtyczki asemblera tworzy wtórny artefakt, który może być trudny do modyfikacji - w moim przypadku chciałem dodać niestandardowe wpisy manifestu. Mój pom skończył jako:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <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>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>
Matthew Franglen
źródło
1
Bardzo miłe! Czy nie lepiej byłoby jednak użyć fazy generowania zasobów do rozpakowywania?
nawroth,
9

Tak powinno być:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Rozpakowanie musi odbywać się w fazie generowania zasobów, ponieważ w fazie pakietowej nie będzie uwzględniane jako zasoby. Wypróbuj czysty pakiet, a zobaczysz.

kac-ani
źródło
7

Masz problem ze zlokalizowaniem udostępnionego pliku zestawu za pomocą maven-assembly-plugin-2.2.1?

Spróbuj użyć parametru konfiguracyjnego descriptorId zamiast parametrów descriptors / descriptor lub descriptorRefs / descriptorRef.

Żadne z nich nie robi tego, czego potrzebujesz: poszukaj pliku na ścieżce klasy. Oczywiście musisz dodać pakiet, w którym znajduje się współużytkowany zestaw, na ścieżce klasy wtyczki maven-assembly-plugin (patrz poniżej). Jeśli używasz Maven 2.x (nie Maven 3.x), może być konieczne dodanie tej zależności w najwyższym nadrzędnym pliku pom.xml w sekcji pluginManagement.

Widzieć to po więcej szczegółów.

Klasa: org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

Przykład:

        <!-- Use the assembly plugin to create a zip file of all our dependencies. -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorId>assembly-zip-for-wid</descriptorId>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>cz.ness.ct.ip.assemblies</groupId>
                    <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>
Rostislav Stříbrný
źródło
7

Aby rozwiązać ten problem, użyjemy wtyczki Maven Assembly Plug, która utworzy plik JAR wraz z jego plikami JAR zależności w jednym pliku wykonywalnym JAR. Wystarczy dodać poniżej konfiguracji wtyczki do pliku pom.xml.

<build>
   <pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.your.package.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>
   </pluginManagement>
</build>

Po wykonaniu tej czynności nie zapomnij uruchomić narzędzia MAVEN za pomocą tego polecenia mvn clean compile assembly: single

http://jkoder.com/maven-creating-a-jar-together-with-its-dependency-jars-into-a-single-executable-jar-file/

Anoop Rai
źródło
5

Nie odpowiem bezpośrednio na pytanie, ponieważ inni już to zrobili, ale naprawdę zastanawiam się, czy dobrym pomysłem jest osadzenie wszystkich zależności w słoju projektu.

Widzę sens (łatwość wdrożenia / użycia), ale zależy to od przypadku użycia twojego obiektu (i mogą istnieć alternatywy (patrz poniżej)).

Jeśli używasz go w pełni autonomicznie, dlaczego nie.

Ale jeśli używasz swojego projektu w innych kontekstach (np. W aplikacji internetowej lub upuszczono w folderze, w którym znajdują się inne słoiki), możesz mieć duplikaty słoików w ścieżce klasy (te w folderze, te w słoikach). Może nie jest to oferta licytacyjna, ale zwykle tego unikam.

Dobra alternatywa:

  • wdróż aplikację jako .zip / .war: archiwum zawiera słoik projektu i wszystkie zależne słoiki;
  • użyj mechanizmu dynamicznego modułu ładującego klasy (patrz Spring, lub możesz to zrobić samemu), aby mieć jeden punkt wejścia do projektu (jedną klasę na początek - zobacz mechanizm manifestu na innej odpowiedzi), który doda (dynamicznie) do bieżąca ścieżka klasy wszystkich innych potrzebnych słoików.

W ten sposób, z końcem tylko manifestem i „specjalnym głównym dynamicznym modułem ładującym klasy”, możesz rozpocząć swój projekt:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
SRG
źródło
1
Jak w takim razie umieścić słoik projektu i wszystkie słoiki zależne w archiwum?
4

Aby utworzyć wykonywalny plik JAR z poziomu wiersza poleceń, wystarczy uruchomić poniższe polecenie ze ścieżki projektu:

mvn assembly:assembly
Mayank
źródło
3
Myślę, że nadal musisz zrobić coś w pom.xmlprzeciwnym razie Error reading assemblies: No assembly descriptors found.. I tak mi się zdarza.
Sridhar Sarnobat
3

To najlepszy sposób, jaki znalazłem:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.myDomain.etc.MainClassName</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
            <goal>copy-dependencies</goal>
        </goals>
        <configuration>
            <outputDirectory>
               ${project.build.directory}/dependency-jars/
            </outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>

Przy tej konfiguracji wszystkie zależności będą znajdować się w /dependency-jars. Moja aplikacja nie ma Mainklasy, tylko kontekstowe, ale jedna z moich zależności ma Mainklasę ( com.myDomain.etc.MainClassName), która uruchamia serwer JMX i odbiera parametr startlub stopparametr. Dzięki temu mogłem uruchomić moją aplikację w następujący sposób:

java -jar ./lib/TestApp-1.0-SNAPSHOT.jar start

Czekam, że przyda się wam wszystkim.

EliuX
źródło
3

Porównałem wtyczki drzewa wspomniane w tym poście. Wygenerowałem 2 słoiki i katalog ze wszystkimi słojami. Porównałem wyniki i zdecydowanie wtyczka maven-shadow-plug jest najlepsza. Wyzwanie polegało na tym, że mam wiele zasobów wiosennych, które musiały zostać połączone, a także jax-rs i usługi JDBC. Wszystkie zostały poprawnie połączone przez wtyczkę cienia w porównaniu z wtyczką maven-assembly-plug. W takim przypadku wiosna nie powiedzie się, chyba że skopiujesz je do własnego folderu zasobów i scalisz je ręcznie jeden raz. Obie wtyczki generują prawidłowe drzewo zależności. Miałem wiele zakresów, takich jak test, dostarczanie, kompilacja itp. Test i dostarczone zostały pominięte przez obie wtyczki. Obaj wyprodukowali ten sam manifest, ale udało mi się skonsolidować licencje z wtyczką cieniowania za pomocą ich transformatora. Z wtyczką zależną od maven oczywiście nie mam te problemy, ponieważ słoiki nie są wyodrębniane. Ale jak niektórzy inni wskazali, musisz mieć jeden dodatkowy plik (i), aby działać poprawnie. Oto wycinek pliku pom.xml

            <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>
                        <includeScope>compile</includeScope>
                        <excludeTransitive>true</excludeTransitive>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</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>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
Fabio
źródło
2

Coś, co zadziałało dla mnie to:

  <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>unpack-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
      </execution>

    </executions>
  </plugin>


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>package</phase>
      </execution>
    </executions>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>SimpleKeyLogger</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

Miałem wyjątkowy przypadek, ponieważ moja zależność dotyczyła systemu pierwszego:

<dependency>
  ..
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/myjar.jar</systemPath>
</dependency>

Zmieniłem kod dostarczony przez @ user189057 ze zmianami: 1) Wtyczka zależności od maven jest wykonywana w fazie „przygotuj pakiet” 2) Wyciągam rozpakowane klasy bezpośrednio do „docelowych / klas”

fascynacja
źródło
2

Spróbowałem tutaj najbardziej głosowanej odpowiedzi i udało mi się uruchomić słoik. Ale program nie działał poprawnie. Nie wiem jaki był tego powód. Kiedy próbuję uciecEclipse , otrzymuję inny wynik, ale kiedy uruchamiam jar z wiersza poleceń, otrzymuję inny wynik (ulega awarii z powodu błędu specyficznego dla programu).

Miałem podobny wymóg jak PO, tylko że miałem zbyt wiele zależności (Maven) dla mojego projektu. Na szczęście jedynym rozwiązaniem, które działało dla mnie, było takie użycie Eclipse. Bardzo proste i bardzo proste. To nie jest rozwiązanie OP, ale rozwiązanie dla kogoś, kto ma podobne wymagania, ale ma wiele zależności Maven,

1) Kliknij prawym przyciskiem myszy folder projektu (w Eclipse) i wybierz Export

2) Następnie wybierz Java ->Runnable Jar

3) Zostaniesz poproszony o wybranie lokalizacji pliku jar

4) Na koniec wybierz klasę, która ma metodę Main, którą chcesz uruchomić, a następnie wybierz Package dependencies with the Jar filei kliknijFinish

Rocky Inde
źródło
2

Może to być również opcja. Będziesz mógł zbudować plik jar

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>WordListDriver</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
salmanbw
źródło
2

Dla każdego, kto szuka opcji wykluczenia określonych zależności z Uber-jar, jest to rozwiązanie, które działało dla mnie:

<project...>
<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.6.1</version>
            <scope>provided</scope> <=============
        </dependency>
</dependencies>
<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>...</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Nie jest to więc konfiguracja wtyczki mvn-assembly-plugin, ale właściwość zależności.

Paul Bormans
źródło
2

Istnieją już miliony odpowiedzi, chciałem dodać, że nie potrzebujesz, <mainClass>jeśli nie musisz dodawać entryPoint do swojej aplikacji. Na przykład interfejsy API niekoniecznie muszą mieć mainmetodę.

Konfiguracja wtyczki maven

  <build>
    <finalName>log-enrichment</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

budować

mvn clean compile assembly:single

zweryfikować

ll target/
total 35100
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ./
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ../
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 archive-tmp/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 classes/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-sources/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-test-sources/
-rwxrwx--- 1 root vboxsf 35929841 Sep 29 16:10 log-enrichment-jar-with-dependencies.jar*
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 maven-status/
prayagupd
źródło
2

Dodaj do pom.xml:

  <dependency>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
  </dependency>

i

<plugin>
       <groupId>com.jolira</groupId>
       <artifactId>onejar-maven-plugin</artifactId>
       <version>1.4.4</version>
       <executions>
              <execution>
                     <goals>
                         <goal>one-jar</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

Otóż ​​to. Następny pakiet mvn utworzy dodatkowo jeden słoik tłuszczu, w tym wszystkie słoiki zależności.

Aydin K.
źródło
1

Wtyczka maven-assembly-plug działała dla mnie świetnie. Spędziłem godziny z wtyczką zależności od raju i nie mogłem sprawić, by działała. Głównym powodem było to, że musiałem wyraźnie zdefiniować w sekcji konfiguracji elementy artefaktu, które powinny zostać uwzględnione zgodnie z opisem w dokumentacji . Jest tam przykład przypadków, w których chcesz go użyć, takich jak:, mvn dependency:copygdzie nie ma żadnych artefaktów, ale to nie działa.

Chris
źródło
1

Ten post na blogu pokazuje inne podejście do łączenia wtyczek maven-jar i maven-assembly. Za pomocą xml konfiguracji zestawu z posta na blogu można również kontrolować, czy zależności będą rozszerzane, czy tylko gromadzone w folderze i wskazywane przez wpis ścieżki klasy w manifeście:

Idealnym rozwiązaniem jest umieszczenie słoików w folderze lib, a plik manifest.mf słoika głównego zawiera wszystkie słoiki w ścieżce klasy.

I dokładnie ten jest opisany tutaj: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/

Jan Ziegler
źródło
0
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Shang Gao
źródło
1
Potrzebujesz trochę więcej tego wyjaśnienia; czy te komentarze są tylko dokumentacją, czy też muszą istnieć dodatkowe opcje w lokalizacjach tych komentarzy?
Mark Stewart
-2

Okej, więc to jest moje rozwiązanie. Wiem, że nie używa pliku pom.xml. Miałem jednak problem z tym, że mój program kompilował się i działał na Netbeans, ale nie działał, kiedy próbowałem Java -jar MyJarFile.jar. Teraz nie do końca rozumiem Maven i myślę, że dlatego miałem problem z włączeniem mojego pliku jar do biblioteki Netbeans 8.0.2 w celu umieszczenia go w pliku jar. Myślałem o tym, jak używałem plików jar bez Maven w środowisku Eclipse.

To Maven może kompilować wszystkie zależności i wtyczki. Nie Netbeans. (Jeśli możesz uzyskać Netbeans i móc użyć do tego java .jar, proszę powiedz mi jak (^. ^) V)

[Rozwiązane - dla systemu Linux] poprzez otwarcie terminala.

Następnie

cd /MyRootDirectoryForMyProject

Kolejny

mvn org.apache.maven.plugins:maven-compiler-plugin:compile

Kolejny

mvn install

Spowoduje to utworzenie pliku jar w katalogu docelowym.

MyJarFile-1.0-jar-with-dependencies.jar

Teraz

cd target

(Może być konieczne uruchomienie: chmod +x MyJarFile-1.0-jar-with-dependencies.jar )

I w końcu

java -jar MyJarFile-1.0-jar-with-dependencies.jar

Proszę zobaczyć

https://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException

Zamieszczę to rozwiązanie na kilku innych stronach z podobnym problemem. Mam nadzieję, że uda mi się uratować kogoś przed tygodniem frustracji.

mycowan
źródło
2
Spróbuj otworzyć projekt Maven utworzony za pomocą Netbeans. Podstawową zasadą Netbeans jest zawsze tworzenie projektu Maven, a nigdy „aplikacja Java”. Dodanie wtyczki maven-shadow jak jednej z odpowiedzi. Działa jak marzenie.
rjdkolb