Питання Як я можу створити виконуваний JAR з залежностями, використовуючи Maven?


Я хочу скласти свій проект у єдиний виконуваний JAR для розповсюдження.

Як я можу зробити пакунок проекту Maven всі JAR-залежності у вихідний JAR?


1944
2018-02-22 08:43


походження


Будь ласка, поясніть, яка мета плагіна залежностей, про який ви маєте на увазі. Я не знаю жодної мети, яка робить те, що запитує оригінальне запитання: поставити всі залежностi або A) всередині автора через перепакування, або B) зробити виконуваний банок, який має інших у path class з MANIFEST.MF - Matthew McCullough
Ви можете знайти це корисно rationaljava.com/2015/02/... - Dan
2 приклади: tugay.biz/2015/12/a-standalone-java-web-application-with.html  tugay.biz/2016/11/how-did-i-create-executable-jar-with.html - Koray Tugay
Зверніться stackoverflow.com/questions/35217128/... - Thanga


Відповіді:


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

і ви запустите його

mvn clean compile assembly:single

Мета компіляції слід додати до монтажу: одне або інше, код на ваш власний проект не включається.

Докладніше в коментарях.


Зазвичай ця мета пов'язана з фазою збірки, яка виконується автоматично. Це гарантує, що JAR будується при виконанні mvn install або виконання розгортання / випуску.

<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



Спасибі @ Адаптер. Зверніть увагу, що ви завжди повинні робити компіляцію перед рукою, оскільки вона просто поставить все, що знаходиться в "target / classes" в JAR. Це гарантує, що JAR включатиме будь-які внесені вами зміни до вихідного коду. Отже, ви повинні зробити щось подібне: mvn clean compile assembly:single. - Michael
Я відредагував питання, щоб включити фазовий зв'язок. Я видалив незмінну ціль збірки, тому що ніхто не повинен знати про це. - Duncan Jones
Я бачу, що це не додає банки до uber-jar, замість цього це просто додає всі файли класу до банку. - pitchblack408
Порада: ви також можете додати елемент <appendAssemblyId>false</appendAssemblyId> в configuration щоб уникнути здивованого суфіксу "-jar-with-dependencies" в назві - maxivis
забувай compile і ви загвинчуєте. - prayagupd


Ви можете використовувати залежність-плагін для генерації всіх залежностей в окремому каталозі перед початком етапу пакетування, а потім включити його в шлях до класу маніфесту:

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

Альтернативно можна використовувати ${project.build.directory}/classes/lib як OutputDirectory, щоб інтегрувати всі jar-файли в основну банку, але тоді вам потрібно буде додати власний код завантаження класів для завантаження банок.


294
2018-06-02 03:01



+1 Відмінно. Причина, з якою я йду з Maven-dependency-plugin замість Maven-Assembly-plugin, полягає в тому, що я також використовую buildnumber-Maven-plugin, і таким чином я можу окремо зберігати номер версії в маніфесті кожного банку. - PapaFreud
Мені подобається Ваше рішення. я використовую ${project.build.directory}/classes/lib як outputDirectory мати один основний .jar з усіма залежностями всередині, але - Як додати власний код завантаження класів для завантаження цих банок? Мені потрібно виконати роботу, як: java -jar main-jar-with-deps.jar. Чи це можливо? - marioosh
@ Андре Аронсен, я використовував це рішення для додавання залежностей у папку lib всередині банку, але я завжди отримую клас не знайшов винятку, чи можете ви порадити, як це виправити. - Mahmoud Saleh
+1 до вас !! Схоже, плагін Maven монтажу 'jar-with-dependencies' насправді не працює добре. У сформованому баночку мені не вистачало деяких записів з META-INF / spring.schemas. Таким чином, я зняв з барана з-залежності і використовував ваше рішення вище. Прекрасне спасибі !!! - Derek
Щоб хто-небудь, хто зіткнувся з цією проблемою, потрібно включити папку lib у той самий каталог з вашим банком, де ви транспортуєте банку. - Sparticles


Я блогів про деякі різні способи зробити це.

Побачити Виконаний джар з Apache Maven (WordPress)

або executable-jar-with-maven-example (GitHub)

Примітки

Ці плюси і мінуси надаються Стефан.


Для ручного розгортання

  • Плюси
  • Мінусів
    • Залежність виходить з остаточної банки.

Копіювати залежності в певний каталог

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

Зробіть Jar executable та Classpath Aware

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

На цьому місці jar дійсно виконуваний з зовнішніми елементами path classp.

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

Зробити розгортання архівів

The jar файл виконується тільки з братом або братом ...lib/ каталог Ми повинні зробити архіви для розгортання з каталогом та його вмістом.

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

Тепер у вас є target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz) кожен з яких містить jar і lib/*.


Apache Maven Assembly Plugin

  • Плюси
  • Мінусів
    • Немає підтримки класу переміщення (використовуйте Maven-shade-плагін, якщо потрібен переміщення класу).
<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>

Ти маєш target/${project.bulid.finalName}-jar-with-dependencies.jar.


Apache Maven Тіньовий плагін

  • Плюси
  • Мінусів
<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>

Ти маєш target/${project.build.finalName}-shaded.jar.


Onejar-Maven-плагін

  • Плюси
  • Мінусів
    • Не активно підтримується з 2012 року.
<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>

Весна Boot Maven плагін

  • Плюси
  • Мінусів
    • Додайте потенційні необов'язкові класи, пов'язані з весною та весною.
<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>

Ти маєш target/${project.bulid.finalName}-spring-boot.jar.


134
2018-02-26 04:31



Єдиний, хто працює для мене - це ручне розгортання. - caiohamamura
@caiohamamura Ви можете клонувати GitHub Репозиторій і подивіться, як працюють всі профілі. - Jin Kwon
Проблема була в тому, що я використовував пакет: stackoverflow.com/a/12622037/2548351 - caiohamamura


Отримавши відповідь без відповіді і переформатуючи її, ми маємо:

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

Далі, я рекомендую зробити це природною частиною вашої збірки, а не щось називати явним. Щоб зробити це невід'ємною частиною вашої збірки, додайте цей плагін у свій pom.xml і пов'яжіть його з package життєвий цикл. Однак, готча є те, що вам потрібно зателефонувати assembly:single Мета, якщо це помістити в ваш pom.xml, тоді як ви називаєте 'assembly: assembly', якщо виконувати його вручну з командного рядка.

<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



Використовуючи підхід у цій відповіді, з'являється таке повідомлення про помилку: "Не вдалося завантажити атрибут маніфесту основного класу з <jar file>" при спробі запустити JAR, використовуючи "java-jar <jar file>" - Elmo
Архів частина Maven-jar-plugin потрібна <archive> <manifest> <addClasspath> true </ addClasspath> <mainClass> fully.qualified.MainClass </ mainClass> </ manifest> </ archive> - RockyMM
На жаль, ця відповідь здається неправильною, тег mainClass має бути на вході Maven-assembly-plugin, оскільки ви телефонуєте, що під час цілі пакету - Alex Lehmann
@ AlexLehmann true! - RockyMM
Я здивований, чому не може pom.xml вже включити це після mvn архетипу: генерувати команду? Це різновид дратує вручну copy-paste це кожного разу коли я створюю новий проект maven ... - wintermute


Використовуйте плагін maven-shade для того, щоб упакувати всі залежно-сті в одну uber-jar. Він також може бути використаний для створення виконуваного банку, вказавши основний клас. Після спроби використати maven-assembly та maven-jar я виявив, що цей плагін найкраще підходить моїм потребам.

Я виявив, що цей плагін особливо корисний, оскільки він об'єднує вміст певних файлів, а не перезаписує їх. Це потрібно, коли у файлах ресурсів є однакові назви в банках, і плагін намагається упакувати всі файли ресурсів

Див нижче приклад

      <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



Як же bcprov-jdk15.jar потрапляє в path classpath під час виконання, оскільки він виключений із процесу затінення? - Andrew Swan
Це ставало затягуванням cxf-rt-ws-security, що є частиною моїх залежностей - Vijay Katam
Ніколи не чули про цей плагін раніше, але це вирішило мою проблему з spring.handlers у банках. Дякую! - Alexandre L Telles
Ті, хто отримав виняток безпеки, виключають DSA з Маніфесту. Перевірте maven.apache.org/plugins/maven-shade-plugin/examples/... - ruhsuzbaykus
+1 Я використовував minijar: ueberjar в минулому, але плагін minijar тепер застарілий і замінено тіні - rds


Довгий час використовувався Maven плагін збирання, але я не міг знайти вирішення проблеми з "already added, skipping". Тепер я використовую інший плагін - Onejar-Maven-плагін. Приклад нижче (mvn package створити банку):

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

Вам потрібно додати сховище для цього плагіна:

<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



як позбутися від додаткових повідомлень у виводі? - Alexandr


Ви можете використовувати Maven-dependency-plugin, але питання полягало в тому, як створити виконуваний JAR. Для цього потрібна наступна зміна відповіді Метью Франглен (до речі, за допомогою плагіна залежностей потрібно більше часу будувати, коли починається з чистої мети):

<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