Вопрос-ответ

How can I create an executable/runnable JAR with dependencies using Maven?

Как я могу создать исполняемый / управляемый файл JAR с зависимостями с помощью Maven?

Я хочу упаковать свой проект в один исполняемый файл JAR для распространения.

Как я могу заставить проект Maven упаковать все банки зависимостей в мою выходную JAR?

Переведено автоматически
Ответ 1
<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 или выполнении развертывания / выпуска.

<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>
<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>
</plugins>
</build>
Ответ 2

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

<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 в основной файл JAR, но тогда вам нужно будет добавить пользовательский код загрузки классов для загрузки файлов JAR.

Ответ 3

Смотрите executable-jar-with-maven-example (GitHub)

Примечания

Эти плюсы и минусы предоставлены Стефаном.


Для ручного развертывания


  • Плюсы

  • Минусы

    • Зависимости отсутствуют в финальном jar.



Скопируйте зависимости в определенный каталог

<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 и путь к классу

<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 фактически является исполняемым с внешними элементами classpath.

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

Создание развертываемых архивов

Файл 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


  • Плюсы

  • Минусы

    • Нет поддержки перемещения классов (используйте maven-shade-plugin, если требуется перемещение классов).



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

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


Apache Maven Shade Plugin


  • Pros

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

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


onejar-maven-plugin


  • Плюсы

  • Минусы

    • Не поддерживается активно с 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>

Плагин Spring Boot Maven


  • Плюсы

  • Минусы

    • Добавьте потенциально ненужные классы, связанные с Spring и 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>

У вас есть target/${project.bulid.finalName}-spring-boot.jar.


Плагин Quarkus Maven


  • Плюсы

  • Минусы

<plugin>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<skipOriginalJarRename>true</skipOriginalJarRename> <!-- keep the original jar without .origin -->
<properties>
<quarkus.native.container-build>false</quarkus.native.container-build>
<quarkus.package.type>uber-jar</quarkus.package.type>
<quarkus.package.main-class>${mainClass}</quarkus.package.main-class>
<quarkus.package.output-directory>${project.build.directory}</quarkus.package.output-directory>
<quarkus.package.runner-suffix>-quarkus</quarkus.package.runner-suffix>
</properties>
</configuration>
<executions>
<execution>
<id>uber-jar</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>

У вас есть target /${project.bulid.finalName}-quarkus.jar.

Ответ 4

Принимая ответ IAdapter и переформатируя его, мы имеем:

<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: сборка', если выполняете ее вручную из командной строки.

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