Как создать исполняемый JAR с помощью Maven

Maven – это инструмент сборки Java-проектов: он компилирует исходники, подключает зависимости и создает JAR. Чтобы запустить архив через java -jar, добавьте класс с методом main и выберите способ упаковки. Здесь разобраны 5 вариантов: обычный JAR, папка libs, Assembly, Shade и Spring Boot.

Вы получите команды сборки, имена итоговых файлов и способы проверки. Maven читает pom.xml, запускает фазы сборки и управляет зависимостями проекта.

Подготовка проекта Maven

Возьмите Maven-проект с типом упаковки jar. Для примеров используйте координаты ru.internettechnologies:executable-jar:1.0-SNAPSHOT и класс ru.internettechnologies.jarapp.ExecutableMavenJar.

<groupId>ru.internettechnologies</groupId>
<artifactId>executable-jar</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

Добавьте свойства компиляции и итоговое имя в существующие блоки properties и build. Второй блок build в том же POM не создавайте.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
</properties>

<build>
    <finalName>executable-jar-1.0-SNAPSHOT</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <release>${maven.compiler.release}</release>
            </configuration>
        </plugin>
    </plugins>
</build>

Родительский POM может управлять версиями плагинов через pluginManagement. Выполните mvn help:effective-pom рядом с pom.xml и убедитесь, что для используемых плагинов заданы версии. В примерах ниже применяйте maven-jar-plugin, maven-dependency-plugin, maven-assembly-plugin, maven-shade-plugin и Spring Boot с версиями из effective POM.

Создайте файл src/main/java/ru/internettechnologies/jarapp/ExecutableMavenJar.java. Пакет, имя класса и значение mainClass должны совпадать.

package ru.internettechnologies.jarapp;

public class ExecutableMavenJar {
    public static void main(String[] args) {
        System.out.println("Приложение запущено");
    }
}

Оставьте в build.plugins compiler-плагин и добавляйте только один способ упаковки за раз. Команда mvn -v покажет Java, которую использует Maven.

maven jar plugin для JAR без зависимостей

maven jar plugin подходит приложению, которому хватает классов JDK. Плагин записывает поле Main-Class в манифест обычного JAR.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <mainClass>ru.internettechnologies.jarapp.ExecutableMavenJar</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>
  1. Добавьте плагин в build.plugins и удалите другие плагины упаковки.
  2. Выполните mvn clean package. Maven создаст target/executable-jar-1.0-SNAPSHOT.jar.
  3. Запустите java -jar target/executable-jar-1.0-SNAPSHOT.jar. В консоли появится «Приложение запущено».

Обычный JAR содержит классы проекта и манифест. Внешние библиотеки он не включает.

maven dependency plugin и папка libs

maven dependency plugin копирует зависимости в отдельный каталог. Манифест добавляет этот каталог в classpath, поэтому рядом с JAR нужна папка libs.

<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>
            <configuration>
                <includeScope>runtime</includeScope>
                <outputDirectory>${project.build.directory}/libs</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>libs/</classpathPrefix>
                <mainClass>ru.internettechnologies.jarapp.ExecutableMavenJar</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>
  1. Добавьте оба плагина в build.plugins и уберите другие варианты упаковки.
  2. Выполните mvn clean package. Maven создаст target/executable-jar-1.0-SNAPSHOT.jar и каталог target/libs.
  3. Запустите результат из проекта командой java -jar target/executable-jar-1.0-SNAPSHOT.jar.
  4. Создайте отдельный каталог комплекта и скопируйте в него JAR.
  5. Скопируйте каталог target/libs рядом с JAR под именем libs.
  6. Откройте каталог комплекта и выполните java -jar executable-jar-1.0-SNAPSHOT.jar.

Рабочая структура содержит JAR и libs на одном уровне. Если положить библиотеки рядом без этой папки, пути манифеста перестанут совпадать.

maven assembly plugin для fat-JAR

maven assembly plugin объединяет классы проекта и зависимости в один архив. Дескриптор jar-with-dependencies подходит простому приложению без relocation.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>ru.internettechnologies.jarapp.ExecutableMavenJar</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </execution>
    </executions>
</plugin>

Цель single запускается на фазе package и создает сборку по выбранному дескриптору. В текущей конфигурации этот способ использует встроенный дескриптор jar-with-dependencies.

  1. Добавьте Assembly в build.plugins и удалите другие плагины упаковки.
  2. Выполните mvn clean package.
  3. Найдите target/executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar.
  4. Запустите java -jar target/executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar. Приложение выведет «Приложение запущено».

Папка libs для Assembly не нужна. Плагин удобен для простого fat-JAR, но не переносит конфликтующие пакеты.

maven shade plugin для fat-JAR и relocation

maven shade plugin собирает uber-JAR и переносит пакеты выбранных зависимостей. Relocation снижает риск конфликта одинаковых имен пакетов.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <id>shade</id>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <shadedClassifierName>shaded</shadedClassifierName>
                <createDependencyReducedPom>false</createDependencyReducedPom>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>ru.internettechnologies.jarapp.ExecutableMavenJar</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

Параметр shadedArtifactAttached со значением true прикрепляет shaded-архив отдельным артефактом с классификатором и сохраняет основной JAR. Этот параметр не выбирает зависимости.

Для relocation добавьте в configuration блок relocations.

<relocations>
    <relocation>
        <pattern>com.example.library</pattern>
        <shadedPattern>ru.internettechnologies.shaded.library</shadedPattern>
    </relocation>
</relocations>

В pattern укажите пакет зависимости. Пакет собственного приложения переносить не стоит: такой шаг изменит имена его классов.

  1. Замените предыдущий плагин упаковки конфигурацией Shade.
  2. Выполните mvn clean package.
  3. Откройте target и найдите прикрепленный JAR с классификатором shaded.
  4. Запустите найденный файл командой java -jar "target/ИМЯ_АРХИВА.jar", подставив имя целиком.

Основной JAR остается отдельным файлом. Для shaded-архива папка libs не нужна.

spring boot maven и spring boot maven plugin

Связка spring boot maven подходит готовому Spring Boot-проекту. spring boot maven plugin добавляет загрузчик и зависимости в архив во время цели repackage.

Родительский POM spring-boot-starter-parent управляет версией Boot-плагина и подключает execution с идентификатором repackage. Поэтому отдельный execution для этой цели не нужен.

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>ru.internettechnologies.demo.DemoApplication</mainClass>
        <classifier>spring-boot</classifier>
    </configuration>
</plugin>

Замените ru.internettechnologies.demo.DemoApplication полным именем класса приложения. Класс должен запускать Spring Boot через SpringApplication.run.

Classifier spring-boot сохраняет обычный JAR и прикрепляет рядом запускаемый архив с этим classifier. Уберите classifier, если запускаемый архив должен заменить основной артефакт.

  1. Добавьте плагин в build.plugins готового Spring Boot-проекта со spring-boot-starter-parent.
  2. Укажите в mainClass полное имя класса с @SpringBootApplication.
  3. Задайте build.finalName, если хотите управлять основой имени файлов.
  4. Выполните mvn clean package.
  5. В каталоге target найдите архив с суффиксом -spring-boot.
  6. Запустите его командой java -jar "target/ИМЯ_АРХИВА-spring-boot.jar", подставив фактическое имя файла.

Для веб-приложения Spring Boot запускает встроенный сервер из зависимостей проекта. Подробности о цели repackage приведены в документации Spring Boot Maven Plugin.

Какой плагин выбрать

Смотрите на место хранения зависимостей, потребность в relocation и тип проекта. Для приложения без внешних библиотек хватит записи Main-Class в манифесте.

СпособЗависимостиRelocationСложность настройкиАктуальностьИтоговый файл
maven jar pluginСнаружи, если нужныНетНизкаяИспользуетсяexecutable-jar-1.0-SNAPSHOT.jar
maven dependency plugin + maven jar pluginВ папке libsНетСредняяИспользуетсяexecutable-jar-1.0-SNAPSHOT.jar
maven assembly pluginВнутри JARНетНизкаяИспользуетсяexecutable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar
maven shade pluginВнутри JARДаСредняяИспользуетсяJAR с classifier shaded
spring boot maven pluginВнутри запускаемого архиваНетСредняяДля Spring BootАрхив с суффиксом -spring-boot

Берите maven jar plugin, если приложению хватает классов JDK. Выбирайте maven dependency plugin, когда библиотеки нужно хранить отдельно. Assembly подходит простому fat-JAR, Shade – проекту с relocation, а Spring Boot – готовому приложению на Spring Boot.

Ошибка no main manifest attribute, in ...jar

Сообщение no main manifest attribute, in ...jar означает, что манифест не содержит поля Main-Class. Java не знает, какой класс запускать.

  1. Откройте исходный класс и найдите метод public static void main(String[] args).
  2. Сравните строку package с полным именем в mainClass.
  3. Проверьте, что выбранный плагин находится в build.plugins.
  4. Выполните mvn clean package, чтобы удалить старый архив.
  5. Запустите архив выбранного способа. Для Spring Boot возьмите JAR с суффиксом -spring-boot, для Shade – с classifier shaded.

Если манифест исправлен, но Java не находит класс библиотеки, обычный JAR не содержит внешние зависимости. Используйте папку libs, Assembly, Shade или Spring Boot.

Как создать jar файл в IntelliJ IDEA

В IntelliJ IDEA откройте окно Maven-проекта и запустите задачи clean и package. Эти задачи выполняют ту же сборку, что и команда mvn clean package.

Если окно Maven не открыто, воспользуйтесь терминалом IDE. Перейдите в каталог с pom.xml и выполните mvn clean package. После успешной сборки Maven покажет BUILD SUCCESS.

Откройте каталог target, выберите архив своего способа и запустите его командой java -jar "target/ИМЯ_АРХИВА.jar". Вместо ИМЯ_АРХИВА.jar вставьте фактическое имя файла.

Как проверить исполняемый JAR

Проверяйте наличие файла и запуск подготовленного комплекта. Для внешних зависимостей тестируйте JAR вместе с папкой libs.

  1. Выполните mvn clean package в каталоге с pom.xml. Maven должен завершить сборку сообщением BUILD SUCCESS.
  2. Откройте target и найдите архив выбранной схемы.
  3. Запустите архив командой java -jar "target/ИМЯ_АРХИВА.jar", подставив фактическое имя.
  4. Скопируйте архив в отдельный каталог. Для схемы с внешними зависимостями перенесите туда и папку libs.
  5. Запустите JAR из нового каталога командой java -jar "ИМЯ_АРХИВА.jar". Учебный класс выведет «Приложение запущено».

Assembly, Shade и Spring Boot не требуют папки libs, когда зависимости попали внутрь запускаемого архива.

Как собрать исполняемый JAR в Maven

Создайте класс с методом main, укажите его полное имя в манифесте и выберите способ упаковки. Затем выполните mvn clean package и запустите архив из каталога target.

Для проекта без внешних библиотек используйте maven jar plugin. Для отдельного комплекта перенесите JAR вместе с папкой libs. Для одного файла выбирайте Assembly или Shade, а для готового Spring Boot-проекта – цель repackage.

Для приложения, которому хватает классов JDK, maven jar plugin – самый простой вариант: его легко проверить, а fat-JAR понадобится после добавления внешних зависимостей.

Комментарии

Оставьте свой комментарий
Boleslav G.

Спасибо, все очень доходчево и ясно и главное работает!