Как создать исполняемый JAR-файл со всеми зависимостями с помощью Maven для удобного распространения моего Java-приложения?
Создание исполняемого JAR со всеми зависимостями с помощью Maven
Для создания исполняемого JAR-файла со всеми зависимостями с помощью Maven можно использовать плагины Maven Assembly Plugin, Maven Shade Plugin или Maven Exec JAR Plugin. Наиболее распространенный подход — использование Maven Shade Plugin, который создает “fat JAR” (жирный JAR), упаковывая все зависимости в один исполняемый JAR-файл, что позволяет запускать ваше приложение с помощью простой команды java -jar your-app.jar.
Содержание
- Использование Maven Shade Plugin
- Использование Maven Assembly Plugin
- Использование Maven Exec JAR Plugin
- Настройка главного класса
- Распространенные проблемы и решения
- Лучшие практики
- Сборка и запуск JAR
Использование Maven Shade Plugin
Maven Shade Plugin — наиболее популярный выбор для создания исполняемых JAR-файлов со всеми включенными зависимостями. Он упаковывает все зависимости в один JAR-файл и также может создавать исполняемый манифест.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.YourMainClass</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Shade Plugin предлагает дополнительные возможности, такие как объединение сервисных файлов и обработка дублирующихся классов через секцию <filters>.
Использование Maven Assembly Plugin
Maven Assembly Plugin — еще один вариант, который создает дистрибутивные пакеты, включая ваш JAR-файл и все зависимости в структуре каталогов.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.YourMainClass</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>
Assembly Plugin создает JAR-файл с суффиксом “-with-dependencies”, который включает все зависимости в той же структуре, в которой они появляются в вашем проекте.
Использование Maven Exec JAR Plugin
Maven Exec JAR Plugin проще и специально ориентирован на создание исполняемых JAR-файлов с правильной конфигурацией classpath.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.example.YourMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.1</version>
<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>
</plugins>
</build>
Этот подход создает отдельный каталог lib для зависимостей вместо их упаковки внутри JAR-файла, что может быть полезно для отладки и управления зависимостями.
Настройка главного класса
Независимо от того, какой плагин вы выберете, вам нужно указать главный класс, который должен выполняться при запуске JAR-файла. Это настраивается в манифесте:
<manifest>
<mainClass>com.example.YourMainClass</mainClass>
</manifest>
Кроме того, вы можете указать главный класс в свойствах вашего pom.xml:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mainClass>com.example.YourMainClass</mainClass>
</properties>
Важно: Убедитесь, что указанный вами главный класс действительно существует в вашем проекте и имеет метод
public static void main(String[] args).
Распространенные проблемы и решения
Дублирующиеся классы
При использовании Shade Plugin вы можете столкнуться с конфликтами дублирующихся классов. Вы можете справиться с этим следующим образом:
<configuration>
<filters>
<filter>
<artifact>com.example:conflicting-library</artifact>
<includes>
<include>com/example/RequiredClass.class</include>
</includes>
</filter>
</filters>
</configuration>
Исключение файлов безопасности
Shade Plugin может не из-за файлов подписи. Исключите их:
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
Проблемы с конфигурацией манифеста
Убедитесь, что ваш манифест правильно настроен с главным классом. Вы можете проверить содержимое манифеста с помощью:
jar tf your-app.jar | grep META-INF/MANIFEST.MF
Лучшие практики
-
Используйте Shade Plugin для создания настоящих fat JAR — это самый надежный способ создать один исполняемый JAR-файл со всеми зависимостями.
-
Исключайте ненужные файлы — удаляйте файлы подписи и записи META-INF для уменьшения размера JAR-файла и избежания конфликтов.
-
Используйте подходящую версию Java — убедитесь, что ваша конфигурация Maven соответствует версии Java, которую вы используете для разработки.
-
Тестируйте ваш JAR — всегда тестируйте созданный JAR-файл в целевой среде развертывания перед распространением.
-
Рассмотрите возможность использования нативных образов — для критически важных по производительности приложений рассмотрите возможность использования GraalVM для создания нативных исполняемых файлов вместо JAR.
-
Используйте управление зависимостями — правильно управляйте вашими зависимостями в секции
dependencyManagementвашегоpom.xmlдля избежания конфликтов версий.
Сборка и запуск JAR
Сборка JAR
После настройки соберите ваш исполняемый JAR-файл с помощью Maven:
mvn clean package
Сгенерированный JAR-файл обычно будет находиться в каталоге target/ с именем вроде your-app-1.0.0.jar или your-app-1.0.0-jar-with-dependencies.jar.
Запуск JAR
Запустите ваш исполняемый JAR-файл с помощью:
java -jar target/your-app-1.0.0-jar-with-dependencies.jar
Проверка зависимостей
Вы можете проверить содержимое вашего JAR-файла, чтобы убедиться, что зависимости включены:
jar tf target/your-app-1.0.0-jar-with-dependencies.jar | head -20
Для более детальной проверки:
jar -tf target/your-app-1.0.0-jar-with-dependencies.jar | grep com/example
Заключение
Создание исполняемого JAR-файла со всеми включенными зависимостями с помощью Maven является простым при правильной настройке плагина. Maven Shade Plugin, как правило, является лучшим выбором для создания настоящих fat JAR, в то время как Assembly Plugin предлагает больше гибкости в вариантах упаковки, а Exec JAR Plugin предоставляет более простой подход с отдельными каталогами для зависимостей.
Ключевые рекомендации:
- Используйте Maven Shade Plugin для большинства приложений, требующих одного исполняемого файла
- Всегда правильно настраивайте главный класс в вашем манифесте
- Тщательно тестируйте ваш JAR-файл перед распространением
- Учитывайте компромиссы между разными подходами в зависимости от ваших потребностей в развертывании
Следуя этим практикам, вы можете легко распространять ваши Java-приложения как самодостаточные исполняемые JAR-файлы, которые работают на любой системе с установленным Java.