Maven llibrary and executable jar
У меня есть Spring-boot приложение, которое собирается мавеном.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/>
</parent>
...
<packaging>jar</packaging>
...
<build>
<finalName>${finalName}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
После сборки получается jar-пакет состава:
и его нельзя подтянуть в другой проект как либу...
а должно получиться:
чтоб каталоги с классами лежали в корне архива.
Как настроить мавен так, чтоб при сборке приложения создавалась еще и библиотека из него?
Ответы (1 шт):
Ваше приложение собралось корректным образом, но раз вы задаете такой вопрос, то мне кажется, что у вас имеются некоторые проблемы с пониманием принципа работы SpringBoot starter'а.
Подключение SpringBoot starter'а:
После подключения spring-boot-maven-plugin в maven pom.xml, плагин автоматически подвяжется на goal spring-boot:repackage, которая запускается на maven phase package, поэтому все должно произойти автоматически при запуске команды mvn package.
Подробнее смотрите здесь.
Как работает SpringBoot starter:
Ваше приложение собирается полностью корректно, просто делом в том, что оно запускается не совсем так, как об этом думаете вы, поясню:
Сборка:
В результате работы maven phase package SpringBoot starter (mvn package):
- maven собирает ваш проект и упаковывает его в .jar-файл (например,
my.jar); - в подключенном
spring-boot-maven-pluginсрабатывает goalrapackage:- переименовывается созданный в п.1 jar-файл в
jar.original(например,my.jar.original); - снова создается jar-файл с оригинальным именем (например,
my.jar):- ваши maven dependency (из
pom.xml) складываются в него (вBOOT-INF/lib); - ваши классы из
jar.originalтакже складываются в него (вBOOT-INF/classes); - служебные классы самого SpringBoot starter'а складываются в корень jar'ника (с учетом java package их размещения);
- ваши maven dependency (из
- переименовывается созданный в п.1 jar-файл в
- все ваши зависимости складываются в каталог
BOOT-INF/libитогового jar'ника; - все ваши скомпилированные классы складываются в каталог
BOOT-INF/classesитогового jar'ника; - все свои скомпилированные классы складываются в корневой каталог итогового jar'ника (
org/springframework/boot/loader); - в файле
META-INF/MANIFEST.MFв качестве основного класса указывает свой собственный (org.springframework.boot.loader.JarLauncher), а не ваш (вопреки вашим ожиданиям), а информацию о ваших классах указывает в других property этого файла:
Пример содержимого файла META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Implementation-Title: spring-boot
Implementation-Version: <версия_вашего_приложения> (например, 0.0.1-SNAPSHOT)
Start-Class: <fully_qualified_name_вашего_стартового_класса> (например, com.test.my.Application)
Spring-Boot-Classes: BOOT-INF/classes/ (сюда попадут ваши классы)
Spring-Boot-Lib: BOOT-INF/lib/ (сюда попадут ваши maven dependency)
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher
Запуск:
В результате запуска исполняемого jar'ника (java -jar <имя_вашего_jar'ника>), получившегося в результате сборки (см. предыдущий пункт) происходит следующее:
- согласно property
Main-ClassизMETA-INF/MANIFEST.MFзапускается main method специально класса SpringBoot starter'а:org.springframework.boot.loader.JarLauncher#main; - этот класс (
org.springframework.boot.loader.JarLauncher#main):- выполняет некоторую предварительную подготовку приложения к запуску;
- получает информацию о вашем приложении из
META-INF/MANIFEST.MF(см. выше):Spring-Boot-Lib- путь размещения используемых вами библиотек (maven dependency);Spring-Boot-Classes- ClassPath ваших классов;Start-Class- fully-qualified name вашего стартового класса, содержащего метод main;
- посредством рефлексии (см.
org.springframework.boot.loader.MainMethodRunner) вызываем методmainвашего стартового класса.
Проверка работы вашего приложения: (после запуска)
Если в вашем приложении имеется хотя бы один RestController, то для того, чтобы удостовериться в том, что приложение корректно поднялось и работает следует его вызвать.
Рассмотрим на следующем примере:
1.приложение поднимается на порту 8080 (default'ное поведение без явного изменения настроек).
2.имеем следующий RestController:
@RestController
public class HelloWorldController {
@RequestMapping("/")
public String helloWorld() {
return "Hello world!";
}
}
Вызываем метод helloWorld, например, одним из следующих образов:
- указываем в окне браузера url
localhost:8080; - используем консольную утилиту
curl, т.е. в командной строке:curl localhost:8080; - используем какое-нибудь приложение (например, Postman или SoapUI).

