Spring Boot 3.5 и 4: подключаем Fory JSON к MVC и WebFlux
Spring Fory 1.1.0 требует Java 17 или новее. Для Boot 4 предназначен
При миграции настройки придётся перенести явно: аннотации Jackson и параметры
Руководство по интеграции показывает API заказов, настройку преобразования JSON и вариант без Spring Boot. Бенчмарки сериализации не гарантируют такой же прирост HTTP-производительности: результат нужно измерять на своём приложении.
Spring Fory 1.1.0 требует Java 17 или новее. Для Boot 4 предназначен
fory-json-spring-boot-starter, для Boot 3.5 — fory-json-spring-boot3-starter. Стартер выбирает интеграцию для MVC или WebFlux, а контроллеры сохраняют привычные @RequestBody, Mono и Flux.При миграции настройки придётся перенести явно: аннотации Jackson и параметры
spring.jackson.* не управляют Fory. Стоит отдельно проверить имена полей и весь JSON-контракт. Ограничение входных данных в MVC относится ко всему телу запроса, а при потоковом NDJSON в WebFlux — к каждому значению в Flux.Руководство по интеграции показывает API заказов, настройку преобразования JSON и вариант без Spring Boot. Бенчмарки сериализации не гарантируют такой же прирост HTTP-производительности: результат нужно измерять на своём приложении.
✍1
JDK 25: как передавать контекст запроса через ScopedValue
В JDK 25 ScopedValue стал постоянным API для идентификаторов запросов, данных пользователя и трассировки. Значение привязывается через
Во вложенной области значение можно временно перепривязать. После её завершения внешняя привязка восстановится, поэтому время жизни контекста видно прямо в коде.
Практический пример с RequestContext показывает проверку через
В JDK 25 ScopedValue стал постоянным API для идентификаторов запросов, данных пользователя и трассировки. Значение привязывается через
where(...).run(...), читается через get() во всей цепочке вызовов и автоматически исчезает после выхода из блока. Это убирает сквозные параметры и ручной ThreadLocal.remove().Во вложенной области значение можно временно перепривязать. После её завершения внешняя привязка восстановится, поэтому время жизни контекста видно прямо в коде.
Практический пример с RequestContext показывает проверку через
isBound() до и после блока. Для миграции ScopedValue подходит читаемому контексту с ограниченным временем жизни. ThreadLocal остаётся для изменяемого состояния потока, прежних версий Java и совместимости с существующими API.JDK 26: когда автовекторизации JIT мало и нужен Vector API
JIT превращает циклы Java в SIMD-инструкции, обрабатывающие несколько чисел за раз. На JDK 26.0.2.1 и Apple M4 Max суммирование миллиона элементов ускорилось примерно вдвое. Вклад оптимизации можно проверить JMH-прогоном с
Vector API с одним аккумулятором дал те же 113 мкс на операцию, а четыре независимых сократили время до 35 мкс: процессору не пришлось ждать предыдущее сложение.
Сравнение JMH-бенчмарков показывает цену ускорения: Vector API остаётся инкубационным, код усложняется, а выигрыш зависит от CPU. Бенчмарк стоит прогнать на production-сервере.
JIT превращает циклы Java в SIMD-инструкции, обрабатывающие несколько чисел за раз. На JDK 26.0.2.1 и Apple M4 Max суммирование миллиона элементов ускорилось примерно вдвое. Вклад оптимизации можно проверить JMH-прогоном с
-XX:-UseSuperWord.Vector API с одним аккумулятором дал те же 113 мкс на операцию, а четыре независимых сократили время до 35 мкс: процессору не пришлось ждать предыдущее сложение.
Сравнение JMH-бенчмарков показывает цену ускорения: Vector API остаётся инкубационным, код усложняется, а выигрыш зависит от CPU. Бенчмарк стоит прогнать на production-сервере.
Как защитить REST API в Spring Boot от несовместимых изменений
В Spring Boot обновление Jackson, смена конфигурации или новая функция могут незаметно нарушить договорённости с клиентами REST API. Контрактные тесты фиксируют ожидаемые запросы и ответы, чтобы поймать расхождение до развёртывания.
Для проверки со стороны провайдера OpenAPI-Diff сравнивает текущую спецификацию со снимком. Метод
Spring Cloud Contract хранит контракты в YAML, а Maven-плагин генерирует проверочные тесты и WireMock-заглушки для клиентов. Если команда контролирует потребителей API, можно передать им ведение контракта через Pact. Практический разбор трёх подходов помогает выбрать схему и настроить проверки совместимости.
В Spring Boot обновление Jackson, смена конфигурации или новая функция могут незаметно нарушить договорённости с клиентами REST API. Контрактные тесты фиксируют ожидаемые запросы и ответы, чтобы поймать расхождение до развёртывания.
Для проверки со стороны провайдера OpenAPI-Diff сравнивает текущую спецификацию со снимком. Метод
isCompatible(), в отличие от строгого isUnchanged(), не отклоняет совместимое добавление новых эндпоинтов.Spring Cloud Contract хранит контракты в YAML, а Maven-плагин генерирует проверочные тесты и WireMock-заглушки для клиентов. Если команда контролирует потребителей API, можно передать им ведение контракта через Pact. Практический разбор трёх подходов помогает выбрать схему и настроить проверки совместимости.
👍1😁1👌1
DAGP 3.5.0 проверяет бинарную совместимость дубликатов классов в Gradle
Если два JAR содержат класс с одинаковым полным именем, JVM загрузит первый найденный в пути классов. Поэтому порядок зависимостей может решить, какая реализация попадёт в работу. На этом же поведении строятся атаки Maven-Hijack.
Dependency Analysis Gradle Plugin запускает проверку через
Разбор проверки Gradle-сборки предлагает предупреждать о дубликатах либо останавливать сборку. Ограничение остаётся: вредоносная реализация с прежними сигнатурами пройдёт такую проверку, поэтому DAGP служит ранним сигналом, а не полной защитой.
Если два JAR содержат класс с одинаковым полным именем, JVM загрузит первый найденный в пути классов. Поэтому порядок зависимостей может решить, какая реализация попадёт в работу. На этом же поведении строятся атаки Maven-Hijack.
Dependency Analysis Gradle Plugin запускает проверку через
buildHealth. При обнаружении дубликатов DAGP 3.5.0 сравнивает поля и методы классов, включая типы, параметры и модификаторы. Несовместимые сигнатуры помогают найти конфликт версий, ошибочную перепаковку библиотеки или подозрительную подмену класса.Разбор проверки Gradle-сборки предлагает предупреждать о дубликатах либо останавливать сборку. Ограничение остаётся: вредоносная реализация с прежними сигнатурами пройдёт такую проверку, поэтому DAGP служит ранним сигналом, а не полной защитой.
Spring Boot 4: настраиваем экспорт логов, метрик и трассировок через OpenTelemetry
В Spring Boot 4 появился собственный OpenTelemetry starter. Spring рекомендует его вместо Java-агента и стороннего starter с альфа-зависимостями.
Для логов нужны Logback appender,
Метрики потребуют Micrometer и дополнительных bean-компонентов, для трассировок достаточно адреса экспорта. Полная схема настройки включает Docker Compose с Grafana LGTM. Проверьте адрес логов: нужен
В Spring Boot 4 появился собственный OpenTelemetry starter. Spring рекомендует его вместо Java-агента и стороннего starter с альфа-зависимостями.
Для логов нужны Logback appender,
logback-spring.xml и вызов install(). В 4.0.0 экспорт без Actuator не работал, обе ошибки исправили в 4.0.1.Метрики потребуют Micrometer и дополнительных bean-компонентов, для трассировок достаточно адреса экспорта. Полная схема настройки включает Docker Compose с Grafana LGTM. Проверьте адрес логов: нужен
/v1/logs, не /v1/traces.Как подтвердить взаимную блокировку по дампу потоков Java
Если JVM перестала выполнять работу, снимите несколько дампов с интервалом в несколько секунд:
Найдите потоки в состоянии
Если JVM перестала выполнять работу, снимите несколько дампов с интервалом в несколько секунд:
jcmd <pid> Thread.print -l или jstack -l <pid>.Найдите потоки в состоянии
BLOCKED. Сопоставьте монитор после waiting to lock с потоком, который держит его после locked. Если цепочка вернулась к первому потоку, взаимная блокировка подтверждена.WAITING и TIMED_WAITING сами по себе нормальны. Практический разбор дампов показывает, как сверить стеки с метриками. Исправлять нужно порядок захвата блокировок: увеличение пула цикл не разорвёт.❤1🔥1😁1
Как StructuredTaskScope в JDK 27 отменяет лишнюю работу при сбое
Два независимых вызова к сервисам последовательно занимают около двух секунд. Виртуальные потоки с
Сравнение трёх реализаций учитывает седьмую предварительную версию API в JDK 27 и проверяемое исключение
Два независимых вызова к сервисам последовательно занимают около двух секунд. Виртуальные потоки с
Future сокращают успешный запуск примерно до секунды, но при сбое одного вызова через 200 мс второй продолжает работу. Закрытие ExecutorService ждёт его завершения, хотя результат уже не нужен.StructuredTaskScope объединяет подзадачи: ошибка одной прерывает соседнюю, а join() сообщает о сбое всей группы. В примере метод возвращается примерно через 200 мс вместо полной секунды.Сравнение трёх реализаций учитывает седьмую предварительную версию API в JDK 27 и проверяемое исключение
ExecutionException. Для запуска нужен --enable-preview. Ограничение сохраняется: задача должна реагировать на прерывание, а закрытие области ждёт завершения всех подзадач.🤔1
Как настроить MFA в Spring Security 7 для приложения и отдельных эндпоинтов
Spring Security 7, доступный со Spring Boot 4, добавил
Для MFA во всём приложении аннотация
Чтобы усилить только
Spring Security 7, доступный со Spring Boot 4, добавил
FactorGrantedAuthority. После входа по паролю пользователь получает FACTOR_PASSWORD, а после одноразового токена из письма — FACTOR_OTT. Доступ открывается, когда собраны все обязательные факторы.Для MFA во всём приложении аннотация
@EnableMultiFactorAuthentication связывает фильтры входа и создаёт проверку требуемых факторов. Стандартная форма не умеет задавать их порядок, поэтому для последовательного сценария понадобятся собственные страницы.Чтобы усилить только
/admin/**, аннотации передают пустой список факторов, а отдельный AuthorizationManagerFactory назначают этому маршруту. Остальные запросы сохраняют однофакторную проверку. Конфигурация обоих вариантов приведена с кодом.❤1
JDK 25 и G1: почему Arrays.fill замедлился в 265 раз
В JMH-тесте на Apple M4 Max заполнение массивов ссылок заняло у G1 139 мс, а у ParallelGC 0,5 мс. При этом сборка мусора не запускалась: почти всё время ушло в JIT-код
Причина: барьер записи, который JVM добавляет к каждому присваиванию ссылки. Он помечает изменённые участки кучи, чтобы G1 не сканировал всё старое поколение. На результат также повлияли размер регионов G1 и переход массива в старое поколение.
Разбор JMH-бенчмарка и ARM64-инструкций HotSpot объясняет, почему одной инструкции оказалось недостаточно. Замедление относится к этой конфигурации: перед настройкой G1 повторите замер на своей нагрузке.
В JMH-тесте на Apple M4 Max заполнение массивов ссылок заняло у G1 139 мс, а у ParallelGC 0,5 мс. При этом сборка мусора не запускалась: почти всё время ушло в JIT-код
Arrays.fill.Причина: барьер записи, который JVM добавляет к каждому присваиванию ссылки. Он помечает изменённые участки кучи, чтобы G1 не сканировал всё старое поколение. На результат также повлияли размер регионов G1 и переход массива в старое поколение.
Разбор JMH-бенчмарка и ARM64-инструкций HotSpot объясняет, почему одной инструкции оказалось недостаточно. Замедление относится к этой конфигурации: перед настройкой G1 повторите замер на своей нагрузке.
😁3
Spring Boot 4 и BoxLang: как сохранить CFML-шаблоны при миграции
BoxLang Spring Boot Starter позволяет оставить представления на CFML, языке шаблонов ColdFusion, пока контроллеры и другие части приложения переносятся на Spring. В Maven-проект добавляется стартер версии 1.0.0, а свойство
Контроллер остаётся обычным для Spring MVC: возвращает логическое имя представления, а атрибуты
Это даёт путь для поэтапной миграции без одновременной переписи всех представлений. В готовом примере показаны настройка проекта, передача данных из контроллера и запуск шаблонов на Spring Boot 4.
BoxLang Spring Boot Starter позволяет оставить представления на CFML, языке шаблонов ColdFusion, пока контроллеры и другие части приложения переносятся на Spring. В Maven-проект добавляется стартер версии 1.0.0, а свойство
boxlang.suffix=.cfm переключает его обработчик представлений с файлов .bxm на .cfm.Контроллер остаётся обычным для Spring MVC: возвращает логическое имя представления, а атрибуты
Model автоматически становятся переменными CFML. В шаблонах продолжают работать cfoutput, условия, циклы и подключение общих блоков.Это даёт путь для поэтапной миграции без одновременной переписи всех представлений. В готовом примере показаны настройка проекта, передача данных из контроллера и запуск шаблонов на Spring Boot 4.
👍1
Как измерить экономию памяти от компактных заголовков в Java 27
В Java 27 HotSpot по умолчанию сокращает заголовок объекта с 12 до 8 байт. Но из-за выравнивания по 8 байт объект с одним полем
Воспроизводимый эксперимент сравнивает две JVM с одинаковыми настройками кучи и G1. Java-агент вызывает
Перед уменьшением лимита кучи стоит проверить формы объектов, которые преобладают в сервисе, а затем сравнить живую кучу, нагрузку на GC, задержки и память процесса. Сокращение заголовка само по себе ещё не доказывает экономию ресурсов приложения.
В Java 27 HotSpot по умолчанию сокращает заголовок объекта с 12 до 8 байт. Но из-за выравнивания по 8 байт объект с одним полем
int остался 16-байтным, а с двумя уменьшился с 24 до 16 байт.Воспроизводимый эксперимент сравнивает две JVM с одинаковыми настройками кучи и G1. Java-агент вызывает
getObjectSize() и измеряет только сам объект, без объектов по ссылкам. Во втором запуске компактные заголовки отключаются флагом -XX:-UseCompactObjectHeaders.Перед уменьшением лимита кучи стоит проверить формы объектов, которые преобладают в сервисе, а затем сравнить живую кучу, нагрузку на GC, задержки и память процесса. Сокращение заголовка само по себе ещё не доказывает экономию ресурсов приложения.
👍1
JDK 26: измеряем затраты CPU на сборку мусора
JDK 26 добавляет
Паузы уже не показывают всю цену. В приведённой нагрузке G1 выполнял 79% работы GC конкурентно с приложением. ZGC переносит почти всю тяжёлую работу в конкурентные фазы и держит паузы меньше миллисекунды, но вычисления не исчезают.
В разборе метрики её проверяют через
JDK 26 добавляет
MemoryMXBean.getTotalGcCpuTime(): метод возвращает суммарное процессорное время отдельных потоков GC. Так можно сравнивать размеры кучи на своей нагрузке по затратам сборщика, а не только по длительности пауз.Паузы уже не показывают всю цену. В приведённой нагрузке G1 выполнял 79% работы GC конкурентно с приложением. ZGC переносит почти всю тяжёлую работу в конкурентные фазы и держит паузы меньше миллисекунды, но вычисления не исчезают.
В разборе метрики её проверяют через
-Xlog:cpu на DaCapo и Spring PetClinic. Она учитывает явную работу GC, но не служебный код барьеров в приложении и влияние GC на кэши CPU. Для выбора размера кучи сопоставляйте её с пропускной способностью и задержками.