«1. Обзор
Apache Maven — это широко используемый инструмент управления зависимостями проектов и инструмент построения проектов.
За последние несколько лет Spring Boot стал довольно популярным фреймворком для создания приложений. Существует также подключаемый модуль Spring Boot Maven, обеспечивающий поддержку Spring Boot в Apache Maven.
Мы знаем, что когда мы хотим упаковать наше приложение в артефакт JAR или WAR с помощью Maven, мы можем использовать mvn package. Тем не менее, плагин Spring Boot Maven поставляется с целью переупаковки, и он также вызывается в команде mvn.
Иногда две команды mvn сбивают с толку. В этом уроке мы обсудим разницу между пакетом mvn и spring-boot:repackage.
2. Пример приложения Spring Boot
Прежде всего, мы создадим простое приложение Spring Boot в качестве примера:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Чтобы убедиться, что наше приложение запущено и работает, давайте создадим простой Конечная точка REST:
@RestController
public class DemoRestController {
@GetMapping(value = "/welcome")
public ResponseEntity welcomeEndpoint() {
return ResponseEntity.ok("Welcome to Baeldung Spring Boot Demo!");
}
}
3. Цель пакета Maven
Нам нужна только зависимость spring-boot-starter-web для сборки нашего приложения Spring Boot:
<artifactId>spring-boot-artifacts-2</artifactId>
<packaging>jar</packaging>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
Цель пакета Maven будет принимать скомпилированный код и упакуйте его в распространяемом формате, который в данном случае является форматом JAR:
$ mvn package [INFO] Scanning for projects... [INFO] ------< com.baeldung.spring-boot-modules:spring-boot-artifacts-2 >------ [INFO] Building spring-boot-artifacts-2 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ spring-boot-artifacts-2 --- [INFO] Building jar: /home/kent ... /target/spring-boot-artifacts-2.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ ...
После выполнения команды mvn package мы можем найти встроенный файл JAR spring-boot-artifacts-2.jar в целевом каталоге. . Давайте проверим содержимое созданного файла JAR:
$ jar tf target/spring-boot-artifacts-2.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/baeldung/
com/baeldung/demo/
application.yml
com/baeldung/demo/DemoApplication.class
com/baeldung/demo/DemoRestController.class
META-INF/maven/...
Как видно из приведенного выше вывода, файл JAR, созданный командой mvn package, содержит только ресурсы и скомпилированные классы Java из исходного кода нашего проекта.
Мы можем использовать этот файл JAR как зависимость в другом проекте. Однако мы не можем выполнить файл JAR с помощью java -jar JAR_FILE, даже если это приложение Spring Boot. Это связано с тем, что зависимости времени выполнения не связаны. Например, у нас нет контейнера сервлетов для запуска веб-контекста.
Чтобы запустить наше приложение Spring Boot с помощью простой команды java -jar, нам нужно создать толстый JAR. В этом нам может помочь плагин Spring Boot Maven.
4. Цель repackage плагина Spring Boot Maven
Теперь давайте выясним, что делает spring-boot:repackage.
4.1. Добавление подключаемого модуля Spring Boot Maven
Для выполнения цели переупаковки нам нужно добавить подключаемый модуль Spring Boot Maven в наш файл pom.xml:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
4.2. Выполнение цели spring-boot:repackage
Теперь давайте очистим ранее созданный файл JAR и попробуем spring-boot:repackage:
$ mvn clean spring-boot:repackage
...
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
...
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:repackage (default-cli)
on project spring-boot-artifacts-2: Execution default-cli of goal
org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:repackage failed: Source file must not be null -> [Help 1]
...
К сожалению, это не работает. Это связано с тем, что цель spring-boot:repackage берет существующий архив JAR или WAR в качестве источника и переупаковывает все зависимости времени выполнения проекта внутри окончательного артефакта вместе с классами проекта. Таким образом, переупакованный артефакт становится исполняемым с помощью командной строки java -jar JAR_FILE.jar.
Поэтому нам нужно сначала собрать файл JAR перед выполнением цели spring-boot:repackage:
$ mvn clean package spring-boot:repackage
...
[INFO] Building spring-boot-artifacts-2 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ spring-boot-artifacts-2 ---
[INFO] Building jar: /home/kent/.../target/spring-boot-artifacts-2.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
...
4.3. Содержимое переупакованного файла JAR
Теперь, если мы проверим целевой каталог, мы увидим переупакованный файл JAR и исходный файл JAR:
$ ls -1 target/*jar*
target/spring-boot-artifacts-2.jar
target/spring-boot-artifacts-2.jar.original
Давайте проверим содержимое переупакованного файла JAR: ~ ~~
$ jar tf target/spring-boot-artifacts-2.jar
META-INF/
META-INF/MANIFEST.MF
...
org/springframework/boot/loader/JarLauncher.class
...
BOOT-INF/classes/com/baeldung/demo/
BOOT-INF/classes/application.yml
BOOT-INF/classes/com/baeldung/demo/DemoApplication.class
BOOT-INF/classes/com/baeldung/demo/DemoRestController.class
META-INF/maven/com.baeldung.spring-boot-modules/spring-boot-artifacts-2/pom.xml
META-INF/maven/com.baeldung.spring-boot-modules/spring-boot-artifacts-2/pom.properties
BOOT-INF/lib/
BOOT-INF/lib/spring-boot-starter-web-2.3.3.RELEASE.jar
...
BOOT-INF/lib/spring-boot-starter-tomcat-2.3.3.RELEASE.jar
BOOT-INF/lib/tomcat-embed-core-9.0.37.jar
BOOT-INF/lib/jakarta.el-3.0.3.jar
BOOT-INF/lib/tomcat-embed-websocket-9.0.37.jar
BOOT-INF/lib/spring-web-5.2.8.RELEASE.jar
...
BOOT-INF/lib/httpclient-4.5.12.jar
...
Если мы проверим вывод выше, он намного длиннее, чем JAR-файл, созданный командой mvn package.
Здесь, в перепакованном JAR-файле, у нас есть не только скомпилированные классы Java из нашего проекта, но и все библиотеки времени выполнения, которые необходимы для запуска нашего приложения Spring Boot. Например, встроенная библиотека tomcat упакована в каталог BOOT-INF/lib.
Теперь давайте запустим наше приложение и проверим, работает ли оно:
$ java -jar target/spring-boot-artifacts-2.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
2020-12-22 23:36:32.704 INFO 115154 [main] com.baeldung.demo.DemoApplication : Starting DemoApplication on YK-Arch with PID 11515...
...
2020-12-22 23:36:34.070 INFO 115154 [main] o.s.b.w.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8080 (http) ...
2020-12-22 23:36:34.078 INFO 115154 [main] com.baeldung.demo.DemoApplication : Started DemoApplication in 1.766 seconds ...
Наше приложение Spring Boot запущено и работает. Теперь давайте проверим это, вызвав нашу конечную точку /welcome:
$ curl http://localhost:8080/welcome
Welcome to Baeldung Spring Boot Demo!
Отлично! Получили ожидаемый ответ. Наше приложение работает правильно.
4.4. Выполнение цели spring-boot:repackage во время жизненного цикла пакета Maven
Мы можем настроить подключаемый модуль Spring Boot Maven в нашем pom.xml для переупаковки артефакта на этапе пакета жизненного цикла Maven. Другими словами, когда мы запускаем пакет mvn, spring-boot:repackage будет выполняться автоматически.
«Конфигурация довольно проста. Мы просто добавляем цель переупаковки в исполнительный элемент:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Теперь давайте еще раз запустим mvn clean package:
$ mvn clean package
...
[INFO] Building spring-boot-artifacts-2 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
...
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:repackage (default) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
...
Вывод показывает, что цель переупаковки была выполнена. Если мы проверим файловую систему, мы обнаружим, что переупакованный файл JAR создан:
$ ls -lh target/*jar*
-rw-r--r-- 1 kent kent 29M Dec 22 23:56 target/spring-boot-artifacts-2.jar
-rw-r--r-- 1 kent kent 3.6K Dec 22 23:56 target/spring-boot-artifacts-2.jar.original
5. Заключение
В этой статье мы обсудили разницу между пакетом mvn и spring-boot:repackage.
Кроме того, мы научились выполнять spring-boot:repackage на этапе пакета жизненного цикла Maven.
Как всегда, весь код в этой статье доступен на GitHub.