Włączanie zależności w słoiku z Maven

353

Czy istnieje sposób zmuszenia maven (2.0.9) do włączenia wszystkich zależności do jednego pliku jar?

Mam projekt kompilacji w jednym pliku jar. Chcę, aby klasy z zależności również zostały skopiowane do słoika.

Aktualizacja: Wiem, że nie mogę po prostu dołączyć pliku jar do pliku jar. Szukam sposobu na rozpakowanie słoików określonych jako zależności i spakowanie plików klas do mojego słoika.

biegacz
źródło
2
Jak dołączyć plik jar do pliku jar w maven?
Kush Patel

Odpowiedzi:

488

Możesz to zrobić za pomocą wtyczki maven-assembly z deskryptorem „jar-with-dependencies”. Oto odpowiedni fragment z jednego z naszych pom.xml, który to robi:

  <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>
John Stauffer
źródło
30
attachedCelem jest przestarzała. singleLub directory-singlecelem powinno być preferowane zamiast.
Pascal Thivent
16
directory-singlejest teraz również przestarzałe.
James McMahon
14
użycie singla jest zalecane na oficjalnej stronie internetowej
mateuszb
42
W przypadku, gdy jakikolwiek nowy mvn utknął tak jak ja, dodaj wtyczkę do <plugins> wewnątrz <build>, który jest w <project>.
DA
10
@ Christian.tucker W katalogu docelowym utworzono drugi jar: ./target/example-0.0.1-SNAPSHOT.jar i ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
technokrat
145

W przypadku Maven 2 właściwym sposobem jest skorzystanie z wtyczki Maven2 Assembly, która ma do tego celu wstępnie zdefiniowany plik deskryptora i który można po prostu użyć w wierszu poleceń:

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

Jeśli chcesz, aby ten jar był wykonywalny, po prostu dodaj główną klasę do uruchomienia w konfiguracji wtyczki:

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

Jeśli chcesz utworzyć że zespół jako część normalnego procesu kompilacji, należy powiązać jeden lub katalogów-pojedynczy cel (The assemblycelem powinno być tylko uruchamiany z linii poleceń) do fazy cyklu życia ( packagesens), coś takiego:

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

Dostosuj configurationelement do swoich potrzeb (na przykład z manifestem w formie mówionej).

Pascal Thivent
źródło
Próbuję dokładnie tego, jednak wtyczka nie jest uruchomiona, a plik jar nie jest tworzony, mimo że kompilacja działa płynnie. Czy jest jakaś pułapka, z którą mógłbym utknąć?
posdef
6
To działa dla mnie, ale mam zadanie. po kompilacji tworzone są teraz dwa słoiki, jeden z wersją projektu artefactid, a drugi z wersją artefactid - „jar-with-dependencies”. Ale chcę zbudować tylko jeden słoik. Czy jest jakiś inny sposób
Souvik Bhattacharya
38

Jeśli chcesz wykonać wykonywalny plik jar, muszą one także ustawić klasę główną. Tak powinna być pełna konfiguracja.

    <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>
abdiel
źródło
2
Dlaczego nazwa słoika jest dodawana przez „jar-with-dependencies” ?! Jakieś obejścia?
Tina J
1
@ Tina J możesz dodać <appendAssemblyId>false</appendAssemblyId>wewnątrz <configuration>tagu, aby wykluczyć sufiks „-jar-with-dependencies” w nazwie końcowej.
ccu
19

Jest wtyczka cienia maven . Można go użyć do spakowania i zmiany nazw zależności (w celu pominięcia problemów z zależnościami w ścieżce klasy).

Thomas Jung
źródło
2
jeśli nie lubisz jar-with-dependencies jako części nazwy pliku.
Kyle
zminimalizuj funkcję maven.apache.org/plugins/maven-shade-plugin/examples/…
Alex78191 20.04.2018
to była dla mnie najlepsza odpowiedź .. :)
Anand Varkey Philips
17

Możesz użyć nowo utworzonego słoika za pomocą <classifier>znacznika.

<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>
lasantha
źródło
14

Jeśli (podobnie jak ja) nie podoba ci się opisana powyżej metoda jar-with-dependencies , preferowanym przeze mnie rozwiązaniem jest po prostu zbudowanie projektu WAR, nawet jeśli budujesz tylko samodzielną aplikację Java:

  1. Utwórz normalny projekt jar jar, który zbuduje plik jar (bez zależności).

  2. Ponadto skonfiguruj projekt wojenny maven (z pustym plikiem src / main / webapp / WEB-INF / web.xml , co pozwoli uniknąć ostrzeżenia / błędu w kompilacji maven), który ma tylko twój projekt jar jako zależność i spraw, aby twój projekt jar był <module>pod twoim projektem wojennym. (Ten projekt wojenny jest tylko prostą sztuczką, aby owinąć wszystkie zależności pliku jar w plik zip.)

  3. Zbuduj projekt wojenny, aby utworzyć plik wojenny.

  4. W kroku wdrażania po prostu zmień nazwę pliku .war na * .zip i rozpakuj go.

Powinieneś teraz mieć katalog lib (który możesz przenieść tam, gdzie chcesz) ze słoikiem i wszystkimi zależnościami potrzebnymi do uruchomienia aplikacji:

java -cp 'path/lib/*' MainClass

(Symbol wieloznaczny w ścieżce klasy działa w Javie 6 lub nowszej)

Myślę, że jest to zarówno łatwiejsze do skonfigurowania w maven (nie trzeba się bawić z wtyczką asemblera), a także daje wyraźniejszy widok struktury aplikacji (zobaczysz numery wersji wszystkich zależnych słoików w widoku prostym i unikaj zatykania wszystkiego w jednym pliku jar).

Rop
źródło
Czy to to samo, co Eclipse „Export as Runnable jar”? Ponieważ dzięki temu możesz „spakować wszystkie zależności za pomocą JAR”, a następnie uzyskać wszystkie zależności w folderze project-lib wzdłuż słoika.
WesternGun
@ FaithReaper - To może być „to samo”, nigdy tego nie próbowałem. Ale myślę, że jeśli używasz Eclipse, nie jest łatwo skryptowalne, co jest wymagane, jeśli chcesz wdrożyć automatyczną kompilację + wdrożenie-potok. Na przykład pozwól serwerowi Jenkins wykonać kompilację z repozytorium źródłowego git lub podobnego.
Rop
12

http://fiji.sc/Uber-JAR zapewnia doskonałe wyjaśnienie alternatyw:

Istnieją trzy popularne metody konstruowania pliku Uber-JAR:

  1. Bez cieniowania. Rozpakuj wszystkie pliki JAR, a następnie ponownie je zapakuj w jeden plik JAR.
    • Pro: Działa z domyślnym modułem ładującym klasy Java.
    • Przeciw: Pliki obecne w wielu plikach JAR o tej samej ścieżce (np. META-INF / services / javax.script.ScriptEngineFactory) zastąpią się wzajemnie, co spowoduje nieprawidłowe zachowanie.
    • Narzędzia: Maven Assembly Plugin, Classworlds Uberjar
  2. Zacieniony To samo, co bez cieniowania, ale zmień nazwę (tzn. „Cień”) wszystkich pakietów wszystkich zależności.
    • Pro: Działa z domyślnym modułem ładującym klasy Java. Unika niektórych (nie wszystkich) konfliktów wersji zależności.
    • Przeciw: Pliki obecne w wielu plikach JAR o tej samej ścieżce (np. META-INF / services / javax.script.ScriptEngineFactory) zastąpią się wzajemnie, co spowoduje nieprawidłowe zachowanie.
    • Narzędzia: Wtyczka Maven Shade
  3. JAR of JARs. Końcowy plik JAR zawiera inne pliki JAR osadzone w nim.
    • Pro: Unika kolizji wersji zależności. Wszystkie pliki zasobów są zachowane.
    • Przeciw: Musi spakować specjalny moduł ładujący klasy „bootstrap”, aby umożliwić Java ładowanie klas z opakowanych plików JAR. Debugowanie problemów z modułem ładującym klasy staje się bardziej złożone.
    • Narzędzia: Eksporter plików JAR Eclipse, One-JAR.
André Valenti
źródło
1
Niezupełnie prawda dotycząca usług, wtyczka cieni ma transformatory, a jednym z nich jest łączenie zawartości plików w META-INF/serviceskatalogu. Więcej informacji tutaj: 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>            
Leslie Li
źródło
4

Moje ostateczne rozwiązanie w Eclipse Luna i m2eclipse: Custom Classloader (pobierz i dodaj do swojego projektu, tylko 5 klas): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; ten moduł ładujący jest najlepszy z jednego urządzenia ładującego klasy i bardzo szybki;

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

Edycja w JIJConstants „Rsrc-Class-Path” na „Class-Path”
mvn clean dependence: pakiet zależności kopiowania
jest tworzony jar z zależnościami w folderze lib za pomocą cienkiego modułu ładującego klasy

<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>
Glaucio Southier
źródło
wtyczka maven-dependency <outputDirectory> nie działa, zawsze pisz w folderze „dependence”
Glaucio Southier
utwórz słoik z „zależnością” folderu wewnętrznego zawierającą zależności projektu i umieść go w MANIFEST.MF
Glaucio Southier
<resources> <resource> <directory> src / main / java </directory> <include> <include> ** / *. java </include> <include> ** / *. properties </include> </ obejmuje > </resource> <resource> <directory> src / main / resources </directory> <filtering> true </filtering> <include> <include> ** / * </include> </include> <targetPath> META -INF / </targetPath> </resource> <resource> <directory> $ {project.build.directory} / dependence / </directory> <include> <include> * .jar </include> </include> < targetPath> lib / </targetPath> </resource> </resources>
Glaucio Southier
1
Na podstawie tej odpowiedzi stworzyłem ten projekt. Nie powinieneś zmieniać niczego poza plikiem pom: github.com/raisercostin/jarinjarloader
raisercostin
0

Ten post może być trochę stary, ale ostatnio miałem ten sam problem. Pierwsze rozwiązanie zaproponowane przez Johna Stauffera jest dobre, ale miałem pewne problemy, pracując tej wiosny. Słoiki zależności, których używam wiosną, mają niektóre pliki właściwości i deklarację schematów xml, które mają te same ścieżki i nazwy. Chociaż słoiki te pochodzą z tych samych wersji, jar-with-dependencies maven-goal nadpisywał plik tez ostatnim znalezionym plikiem.

W końcu aplikacja nie mogła się uruchomić, ponieważ słoiki wiosenne nie mogły znaleźć poprawnych plików właściwości. W tym przypadku rozwiązanie zaproponowane przez Ropa rozwiązało mój problem.

Od tego czasu istnieje już projekt Spring-Boot. Ma bardzo fajny sposób na poradzenie sobie z tym problemem, zapewniając cel maven, który przeciąża cel pakietu i zapewnia własny moduł ładujący klasy. Zobacz Przewodnik dotyczący wiosennych butów

Francois Gergaud
źródło
0

Spójrz na tę odpowiedź:

Tworzę instalator, który działa jako plik Java JAR i musi rozpakować pliki WAR i JAR w odpowiednich miejscach w katalogu instalacyjnym. Wtyczka zależności może być używana w fazie pakietu z celem kopiowania i pobierze dowolny plik z repozytorium Maven (w tym pliki WAR) i zapisze je tam, gdzie będziesz ich potrzebować. Zmieniłem katalog wyjściowy na $ {project.build.directory} / klas, a następnie wynik jest taki, że normalne zadanie JAR zawiera moje pliki w porządku. Następnie mogę je wyodrębnić i zapisać w katalogu instalacyjnym.

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

millebi
źródło
0

Dzięki dodałem poniżej fragmentu w pliku POM.xml i problem MP rozwiązany i utwórz gruby plik jar zawierający wszystkie zależne słoiki.

<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>
Rajeev Rathor
źródło