Переход от Spring Boot 3.2 к 3.3 принес изменения в процесс распаковки JAR и запуск приложения в Docker-контейнере.
В новой статье от Рустама Курамшина, эксперта сообщества Spring АйО, вы узнаете:
• что именно изменилось
• как это отразится на создании Dockerfile
• и как адаптировать проекты к новым условиям.
Введение
При разработке приложений на Spring Boot создание docker-образов — частая задача, особенно в современных CI/CD-пайплайнах. Оптимизация сборки этих образов играет ключевую роль, так как позволяет сократить время последующих билдов, эффективно используя кэширование слоев docker-образа. Spring Boot помогает в этом, предоставляя возможность распаковки JAR-архива на отдельные слои: dependencies, spring-boot-loader, snapshot-dependencies и application. Такой подход позволяет перестраивать только измененные части и, например, оставлять зависимости в кэше демона docker.
С переходом от версии Spring Boot 3.2 к 3.3 изменился процесс распаковки JAR и запуска приложения внутри Docker-контейнера. В этой статье мы разберем, что именно поменялось, как это влияет на написание Dockerfile, и как адаптировать свои проекты.
Как это работало в Spring Boot 3.2
В Spring Boot 3.2 для распаковки JAR-файла использовался режим jarmode=layertools
. Команда выглядела так:
java -Djarmode=layertools -jar application.jar extract
Эта команда распаковывала JAR-архив на четыре каталога:
dependencies
— внешние зависимости;spring-boot-loader
— загрузчик Spring Boot;snapshot-dependencies
— зависимости snapshot-версий;application
— код приложения.
После распаковки эти каталоги копировались на отдельные слои в итоговый docker-образ, а приложение запускалось с помощью класса JarLauncher
. Такой подход обеспечивал разделение слоев для эффективного кэширования, но требовал явного указания загрузчика в ENTRYPOINT
в Dockerfile.
Пример Dockerfile для Spring Boot 3.2:
FROM eclipse-temurin:17-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM eclipse-temurin:17-jre
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Процесс прост: JAR-архив распаковывается в рабочей директории, каталоги копируются в итоговый образ, а запуск осуществляется через JarLauncher
.
Что изменилось в Spring Boot 3.3
В Spring Boot 3.3 подход к распаковке и запуску был обновлен.
Основные изменения:
Смена
jarmode
: Вместоjarmode=layertools
теперь используетсяjarmode=tools
.Обновленная команда распаковки: Команда
extract
теперь требует дополнительных опций, таких как--layers
и--destination
, чтобы явно указать директорию для распаковки.
Пример:java -Djarmode=tools -jar my-app.jar extract --layers --destination extracted
Это дает больше контроля над тем, куда распаковываются слои, в отличие от версии 3.2, где распаковка происходила в текущую директорию по умолчанию.
Новый способ запуска: Вместо
JarLauncher
приложение теперь запускается стандартной командойjava -jar application.jar
. Однако важно понимать, чтоapplication.jar
в этом случае — это не исходный "uber JAR", а специальный JAR-файл, содержащий только код приложения и ссылки на распакованные зависимости.
Пример Dockerfile для Spring Boot 3.3:
FROM bellsoft/liberica-openjre-debian:17-cds AS builder
WORKDIR /builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
FROM bellsoft/liberica-openjre-debian:17-cds
WORKDIR /application
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./
ENTRYPOINT ["java", "-jar", "application.jar"]
Обратите внимание на различия:
Использование
jarmode=tools
вместоlayertools
.Явное указание директории распаковки через
--destination extracted
.Переход на
java -jar application.jar
вENTRYPOINT
.
Причины перехода на новый способ запуска распакованных JAR-файлов
Эти изменения делают процесс запуска приложения более стандартизированным. Команда java -jar
— это привычный способ запуска Java-приложений, что упрощает интеграцию с другими инструментами и делает Dockerfile более интуитивным.
Еще одно новшество в Spring Boot 3.3 — поддержка Class Data Sharing (CDS). Это опциональная возможность, которая может ускорить запуск приложения за счет оптимизации загрузки классов, но для целей этой статьи она не является ключевой.
Новый подход позволяет писать CDS-friendly Dockerfile потому что при переходе на использование CDS вам нужно будет интегрировать в Dockerfile тренировочные запуски приложения ("training run") для получения jsa-архива с классами:
RUN java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application.jar
Резюмируем
Если вы обновляете проект с Spring Boot 3.2 до 3.3, вот план адаптации Dockerfile:
Обновите
jarmode
: Заменитеjarmode=layertools
наjarmode=tools
.Добавьте опции в команду распаковки:
Измените
RUN java -Djarmode=tools -jar application.jar extract
на
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
.Измените точку входа:
Замените
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
на
ENTRYPOINT ["java", "-jar", "application.jar"]
.Обновите пути копирования: Убедитесь, что пути в
COPY
соответствуют новой директории распаковки (например,/builder/extracted/
вместоapplication/
).
Заключение
Переход на Spring Boot 3.3 привносит изменения в процесс распаковки JAR и запуска приложений в Docker-контейнерах, делая его более гибким и приближенным к стандартным практикам Java. Обновление Dockerfile при миграции на новую версию
не требует значительных усилий, но важно учесть новые параметры jarmode
и команду запуска.
Для ознакомления с хорошими практиками написания Dockerfiles для Spring Boot предлагаю вам ознакомиться с моим докладом на JPoint 2024 - "Правильный DevOps для Spring Boot и Java":

Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.