Автор оригинала: Gian Mario Contessa.
1. введение
В этом уроке мы рассмотрим различия между запуском веб-приложения Spring Boot с помощью команды mvn spring-boot:run и запуском его после компиляции в пакет jar/war с помощью команды java-jar .
Предположим, что здесь вы уже знакомы с конфигурацией Spring Boot repackage goal. Для получения более подробной информации по этой теме, пожалуйста, прочитайте Создание приложения Fat Jar с помощью Spring Boot .
2. Плагин Spring Boot Maven
При написании приложения Spring Boot Плагин Spring Boot Maven это рекомендуемый инструмент для создания, тестирования и упаковки нашего кода.
Этот плагин поставляется с множеством удобных функций, таких как:
- он решает правильные версии зависимостей для нас
- он может упаковать все наши зависимости (включая встроенный сервер приложений, если это необходимо) в одну выполняемую fat jar/war, а также:
- управляйте для нас конфигурацией пути к классам, чтобы мы могли пропустить этот длинный параметр -cp в нашей команде java -jar
- реализуйте пользовательский загрузчик классов для поиска и загрузки всех внешних библиотек jar, теперь вложенных в пакет
- автоматически найдите метод main() и настройте его в манифесте, поэтому нам не нужно указывать основной класс в нашей команде java -jar
3. Запуск кода с помощью Maven в развернутом виде
Когда мы работаем над веб-приложением, мы можем использовать еще одну очень интересную функцию плагина Spring Boot Maven: возможность автоматического развертывания нашего веб-приложения на встроенном сервере приложений.
Нам нужна только одна зависимость, чтобы плагин знал, что мы хотим использовать Tomcat для запуска нашего кода:
org.springframework.boot spring-boot-starter-web
Теперь при выполнении команды mvn spring-boot:run в корневой папке нашего проекта плагин считывает конфигурацию pom и понимает, что нам требуется контейнер веб-приложения.
Выполнение mvn spring-boot:запуск команда запускает загрузку Apache Tomcat и инициализирует запуск Tomcat.
Давайте попробуем:
$ mvn spring-boot:run ... ... [INFO] --------------------< com.baeldung:spring-boot-ops >-------------------- [INFO] Building spring-boot-ops 0.0.1-SNAPSHOT [INFO] --------------------------------[ war ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.1.3.RELEASE:run (default-cli) > test-compile @ spring-boot-ops >>> Downloading from central: https://repo.maven.apache.org/maven2/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.pom Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.pom (1.8 kB at 2.8 kB/s) ... ... [INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:run (default-cli) @ spring-boot-ops --- ... ... 11:33:36.648 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] 11:33:36.649 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.16] ... ... 11:33:36.952 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext ... ... 11:33:48.223 [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"] 11:33:48.289 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' 11:33:48.292 [main] INFO org.baeldung.boot.Application - Started Application in 22.454 seconds (JVM running for 37.692)
Когда в журнале появляется строка, содержащая “Запущенное приложение”, наше веб-приложение готово к запросу через браузер по адресу http://localhost:8080/
4. Запуск кода в качестве автономного упакованного приложения
Как только мы пройдем этап разработки и захотим продвинуться в направлении запуска нашего приложения в производство, нам нужно будет упаковать наше приложение.
К сожалению, если мы работаем с пакетом jar , базовая цель Maven package не включает никаких внешних зависимостей.
Это означает, что мы можем использовать его только в качестве библиотеки в более крупном проекте.
Чтобы обойти это ограничение, нам нужно использовать плагин Maven Spring Boot repackage goal для запуска нашего jar/war в качестве автономного приложения.
4.1. Конфигурация
Обычно нам нужно только настроить плагин сборки:
... ... org.springframework.boot spring-boot-maven-plugin
Но наш пример проекта содержит более одного основного класса, поэтому мы должны указать Java, какой класс запускать, либо настроив плагин:
org.springframework.boot spring-boot-maven-plugin com.baeldung.webjar.WebjarsdemoApplication
или установив свойство start-class :
com.baeldung.webjar.WebjarsdemoApplication
4.2. Запуск приложения
Теперь мы можем запустить наш пример войны с помощью двух простых команд:
$ mvn clean package spring-boot:repackage $ java -jar target/spring-boot-ops.war
Более подробную информацию о том, как запустить файл jar, можно найти в нашей статье Запуск приложения JAR с аргументами командной строки .
4.3. Внутри файла войны
Чтобы лучше понять, как команда, упомянутая выше, может запускать полное серверное приложение, мы можем взглянуть на наши Чтобы лучше понять, как команда, упомянутая выше, может запускать полное серверное приложение, мы можем взглянуть на наши .
Если мы распакуем его и заглянем внутрь, то найдем обычных подозреваемых:
- META-INF , с автоматически сгенерированным MANIFEST.MF
- WEB-INF/classes , содержащий наши скомпилированные классы
- WEB-INF/lib , в котором хранятся наши военные зависимости и встроенные файлы Tomcat jar
Однако это еще не все, так как есть некоторые папки, специфичные для конфигурации вашего пакета fat:
- WEB-INF/lib-provided , содержащий внешние библиотеки, необходимые при запуске embedded, но не необходимые при развертывании
- org/springframework/boot/loader , который содержит загрузчик пользовательских классов Spring Boot — эта библиотека отвечает за загрузку наших внешних зависимостей и делает их доступными во время выполнения
4.4. Внутри Военного манифеста
Как упоминалось ранее, плагин Maven Spring Boot находит основной класс и генерирует конфигурацию, необходимую для выполнения команды java .
В результирующем файле MANIFEST.MF есть несколько дополнительных строк:
Start-Class: com.baeldung.webjar.WebjarsdemoApplication Main-Class: org.springframework.boot.loader.WarLauncher
В частности, мы можем заметить, что последний из них указывает, какой загрузчик загрузочного класса Spring будет использоваться.
4.5. Внутри файла Jar
Из-за стратегии упаковки по умолчанию наш сценарий war packaging не сильно отличается, независимо от того, используем ли мы плагин Spring Boot Maven или нет.
Чтобы лучше оценить преимущества плагина, мы можем попробовать изменить конфигурацию pom packaging на jar и снова запустить mvn clean package .
Теперь мы можем заметить, что наш fat jar организован немного иначе, чем наш предыдущий файл war:
- Все наши папки классов и ресурсов теперь находятся в папке BOOT-INF/classes
- BOOT-INF/lib содержит все внешние библиотеки
Без плагина, либ папка не будет существовать, и все содержимое BOOT-INF/классы будет находиться в корне пакета.
4.6. Внутри манифеста банки
Также МАНИФЕСТ. MF изменился, включая эти дополнительные строки:
Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 2.1.3.RELEASE Main-Class: org.springframework.boot.loader.JarLauncher
Spring-Boot-Classes и Spring-Boot-Lid особенно интересны, поскольку они говорят нам, где загрузчик классов собирается найти классы и внешние библиотеки.
5. Как выбрать
При анализе инструментов необходимо учитывать цель, для которой эти инструменты созданы. Хотим ли мы облегчить разработку или обеспечить плавное развертывание и переносимость? Давайте посмотрим на фазы, наиболее затронутые этим выбором.
5.1. Развитие
Как разработчики, мы часто тратим большую часть нашего времени на кодирование, не тратя много времени на настройку нашей среды для локального запуска кода. В простых приложениях это обычно не вызывает беспокойства. Но для более сложных проектов нам может потребоваться установить переменные среды, запустить серверы и заполнить базы данных.
Настройка правильной среды каждый раз , когда мы хотим запустить приложение, была бы очень непрактичной , особенно если одновременно должно выполняться несколько служб.
Вот где нам помогает запуск кода с помощью Maven. У нас уже есть вся кодовая база, проверенная локально, поэтому мы можем использовать файлы конфигурации и ресурсов pom. Мы можем установить переменные среды, создать базу данных в памяти и даже загрузить правильную версию сервера и развернуть наше приложение с помощью одной команды.
Даже в многомодульной кодовой базе, где каждому модулю нужны разные переменные и версии сервера, мы можем легко запустить правильную среду с помощью профилей Maven.
5.2. Производство
Чем больше мы продвигаемся к производству, тем больше разговор смещается в сторону стабильности и безопасности. Вот почему мы не можем применить процесс, используемый для нашей машины разработки, к серверу с живыми клиентами.
Запуск кода через Maven на этом этапе является плохой практикой по нескольким причинам:
- Прежде всего, нам нужно будет установить Maven
- Затем, просто потому, что нам нужно скомпилировать код, нам нужен полный комплект разработки Java (JDK)
- Затем мы должны скопировать кодовую базу на наш сервер, оставив весь наш собственный код в виде простого текста
- Команда mvn должна выполнять все фазы жизненного цикла (поиск источников, компиляция и запуск)
- Благодаря предыдущему пункту мы также потратили бы впустую процессор и, в случае облачного сервера, деньги
- Maven порождает несколько процессов Java, каждый из которых использует память (по умолчанию каждый из них использует тот же объем памяти, что и родительский процесс)
- Наконец, если у нас есть несколько серверов для развертывания, все вышесказанное повторяется на каждом из них
Это всего лишь несколько причин, по которым доставка приложения в виде пакета более практична для производства .
6. Заключение
В этом уроке мы рассмотрели различия между запуском нашего кода через Maven и с помощью команды java-jar . Мы также провели краткий обзор некоторых практических сценариев.
Исходный код, используемый в этой статье, доступен на GitHub .