Переход от 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 и всего, что с ним связано.
