Как создать исполняемый JAR-файл с зависимостями с использованием Maven?
Я хочу упаковать свой проект в один исполняемый JAR-файл для распространения.
Как я могу сделать так, чтобы Maven- проект упаковывал все зависимые JAR-файлы в мой выходной JAR?
5 ответ(ов)
Чтобы правильно настроить Maven для сборки вашего проекта с использованием плагина maven-assembly-plugin
, вам нужно добавить соответствующие конфигурации в ваш файл pom.xml
. Вот пример настройки, который включает в себя необходимые секции:
<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> <!-- это используется для объединения наследования -->
<phase>package</phase> <!-- привязка к фазе упаковки -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Как видно из приведенного выше кода, плагин maven-assembly-plugin
настраивается так, чтобы собирать исполняемый JAR, включающий все зависимости вашего проекта. Важно отметить, что цель compile
должна быть выполнена перед выполнением assembly:single
, иначе код вашего проекта не будет включен в сборку.
Для выполнения сборки запустите следующую команду:
mvn clean compile assembly:single
Также стоит упомянуть, что чаще всего вы будете привязывать цель к фазе сборки, что позволяет автоматически выполнять сборку JAR при запуске команды mvn install
или во время развертывания/релиза.
Если вы добавите вышеописанные параметры в ваш pom.xml
, вы гарантируете, что ваш JAR файл будет собираться правильно при соответствующих командах Maven.
Вы можете использовать плагин maven-dependency-plugin
, чтобы сгенерировать все зависимости в отдельной директории перед этапом упаковки, а затем включить эту директорию в класс-путь манифеста. Вот пример конфигурации:
<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-файлов.
Чтобы упаковать все зависимости в один uber-JAR файл, используйте плагин maven-shade-plugin. Он также может быть использован для создания исполняемого JAR файла, указав основный класс. После попыток использовать maven-assembly и maven-jar, я пришёл к выводу, что именно этот плагин лучше всего подходит для моих нужд.
Этот плагин оказался особенно полезным, так как он объединяет содержимое определённых файлов вместо того, чтобы перезаписывать их. Это необходимо, когда в JAR файлах есть файлы ресурсов с одинаковыми именами, и плагин пытается упаковать все файлы ресурсов.
Ниже приведён пример конфигурации:
<plugins>
<!-- Этот плагин предоставляет возможность упаковать
артефакт в uber-JAR файл, включая
его зависимости, и изменить - т.е. переименовать -
пакеты некоторых зависимостей. -->
<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>
<!-- Подписанные JAR файлы-->
<excludes>
<exclude>bouncycastle:bcprov-jdk15</exclude>
</excludes>
</artifactSet>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<!-- Основной класс -->
<mainClass>com.main.MyMainClass</mainClass>
</transformer>
<!-- Используем трансформеры ресурсов для предотвращения перезаписи файлов -->
<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>
В этом примере вы можете увидеть, как конфигурировать плагин, чтобы он собирал зависимости и герметизировал ресурсы, избегая конфликтов имен.
Вы можете использовать плагин maven-shade для создания uber JAR файла следующим образом:
<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>
Этот код нужно добавить в ваш файл pom.xml
. Плагин автоматически объединяет все зависимости вашего проекта в один JAR файл, что упрощает развертывание приложения. Убедитесь, что вы добавили его в правильный раздел <build>
.
Вы можете добавить следующий код в ваш файл pom.xml:
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mycompany.package.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.mycompany.package.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
После этого вам нужно перейти в консоли в директорию, где расположен файл pom.xml. Затем выполните команду mvn assembly:single, и надеюсь, ваш исполняемый JAR-файл с зависимостями будет создан. Вы можете проверить это, перейдя в целевую (target) директорию с помощью cd ./target и запустив ваш JAR с помощью команды, аналогичной java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar.
Я протестировал это на Apache Maven 3.0.3.
Правильный способ добавления внешних JAR-файлов (lib/*.jar) в проект IntelliJ IDEA
Как указать Maven использовать последнюю версию зависимости?
Как работают сервлеты? Инстанцирование, сессии, общие переменные и многопоточность
Возможные значения конфигурации hbm2ddl.auto в Hibernate и их назначение
Что такое PECS (Producer Extends Consumer Super)?