Чашечка Java
前往频道在 Telegram
Лучшие материалы по Java на русском и английском Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels
显示更多8 314
订阅者
-624 小时
-227 天
-6330 天
帖子存档
8 313
Как перенести Spring Boot 3.5 на 4.1 и не пропустить тихие поломки
Поддержка Spring Boot 3.5 закончилась 30 июня 2026 года на версии 3.5.16. При этом проект может собраться и запуститься с устаревшими стартерами: зелёной сборки для миграции недостаточно.
До перехода включите предупреждения об устаревших API и прогоните тесты. Затем проверьте зависимости:
spring-boot-starter-web стал spring-boot-starter-webmvc, а Flyway получил отдельный стартер.
Пошаговая миграция проекта разбирает Jackson 3, переход от MultiValueMap к HttpHeaders и тесты: @MockBean заменён на @MockitoBean, а @SpringBootTest больше не настраивает MockMvc, WebClient и TestRestTemplate. Это чек-лист мест, которые надо проверить после компиляции.8 313
Почему ref = null обычно не помогает сборщику мусора JVM
Локальная ссылка в стеке потока остаётся корнем GC, пока её фрейм активен. После выхода из метода сборщик её не обходит, поэтому
ref = null перед возвратом обычно ничего не меняет.
Сборщик копирует достижимые объекты в другой пул, а прежний затем использует заново. Он сохраняет всё, до чего может добраться от корней, а не удаляет мусор по одному объекту.
Редкое исключение возникает, когда узлы LinkedList лежат в разных поколениях памяти: разрыв связи с обработанной частью иногда сокращает удержание. Но рост памяти требует искать ошибку жизненного цикла: растущую статическую коллекцию, кеш без вытеснения или слушатель без отписки. Разбор стека и достижимости помогает отличить утечку от лишнего присваивания.8 313
Value-классы в JDK 28: где JVM убирает аллокации, а где возвращает их
JEP 401 вошёл в JDK 28 как предварительная возможность. Отказ от идентичности позволяет JVM хранить поля без ссылок и раскладывать компоненты по регистрам или стеку, но ускорение не гарантировано.
Неизменяемые поля JVM может хранить плоско, а для изменяемых выбирает ссылку, чтобы потоки не увидели значение из частей разных записей. JIT-компилятор C2 способен убрать создание value record в цикле, но стирание типов и виртуальный вызов могут вернуть объект и аллокацию.
Перед миграцией проверьте горячие участки и переходы между представлениями: три таких случая разобраны в статье Value Classes Still Need Compiler Sympathy.
8 313
Как показать вызовы инструментов в интерфейсе на Spring AI 2.0
Spring AI 2.0 вынес цикл вызова инструментов из реализаций отдельных моделей в цепочку советников
ChatClient. Теперь его можно обернуть собственным советником, увидеть промежуточные события и показать пользователю, какой метод выполняется до появления ответа модели.
В примере наблюдающий советник ставится перед ToolCallingAdvisor и получает события начала и завершения каждого вызова. Контроллер передаёт их в браузер через серверный поток событий вместе с ответом модели. Память диалога сохраняет контекст между запросами, поэтому следующий вопрос может ссылаться на предыдущий.
В разборе есть рабочий проект на Spring Boot 4.1: инструменты с @Tool, потоковый контроллер и советник для отслеживания вызовов. Подход пригодится, если интерфейсу корпоративного ИИ-сервиса нужна наблюдаемость без изменений внутри модели.8 313
Quarkus 3.29: что изменилось в тестах CDI-компонентов
QuarkusComponentTest запускает не всё приложение, а только CDI-контейнер и сервис конфигурации. Тестируемый бин остаётся реальным, а отсутствующие зависимости автоматически заменяются моками Mockito. Их можно внедрить через @InjectMock и настроить в тестовом методе.
В Quarkus 3.29 переработали загрузку классов. Расширение теперь поддерживает преобразование байткода, упрощённую инъекцию через конструктор, final-классы и методы. Новый SPI позволяет подключать логику до сборки и после запуска контейнера. Интеграция с quarkus-panache-mock добавила компонентные тесты для Panache-сущностей.
В обзоре Quarkus также разобраны жизненный цикл контейнера, автоматический выбор тестируемых компонентов и изменения версий 3.13 и 3.21.8 313
Как Spring AI 2.0 исправляет структурированный вывод по JSON Schema
Обычный
entity(TalkSubmission.class) строит схему из Java-типа и преобразует ответ модели в объект. Если небольшая локальная модель пропустит поле или вернёт недопустимый null, запрос завершится ошибкой 500.
Новый validateSchema(...) сверяет JSON со схемой. При ошибке Spring AI передаёт модели причину и повторяет вызов, по умолчанию до трёх раз. Режим выключен по умолчанию, поэтому существующие вызовы entity после обновления не меняют поведение.
В статье Dan Vega показан пример на Spring Boot с Anthropic и Ollama, а также настройка журнала повторных попыток. Для миграции проверку можно включать точечно там, где нестабильный JSON уже приводит к ошибкам.8 313
Как профилировать Java-приложения с JDK Flight Recorder
JDK Flight Recorder (JFR) встроен в OpenJDK и записывает события JVM с небольшими накладными расходами. Его можно использовать для постоянного наблюдения за приложением, а собранную телеметрию разбирать при снижении производительности или сбоях в продакшене.
Материал показывает, как начать работу с JFR, записать данные и перейти к их анализу. Отдельные сценарии посвящены поиску узких мест, утечек памяти и проблем с потоками. Для долгоживущих Java-сервисов это способ исследовать поведение JVM на данных с работающего приложения.
Практические сценарии и демонстрации собраны в материале Inside.java.
8 313
Quarkus 3.31.2: как измерить покрытие runtime-модулей расширений
До версии 3.31.2 расширение
quarkus-jacoco учитывало код из @QuarkusTest, но не покрытие runtime-модулей в QuarkusUnitTest. Именно такие тесты обычно составляют большинство в расширениях. Причина в сборке: Quarkus применяет офлайн-инструментирование JaCoCo к архивам приложения, а runtime-модуль расширения обычно к ним не относится.
Теперь артефакты для инструментирования можно явно указать через свойства group-id и artifact-id. Для одного расширения конфигурация добавляется в deployment-модуль, после чего отчёт создаётся автоматически.
Для многомодульного проекта статья показывает, как собирать данные всех тестов в общий файл и строить единый отчёт по зависимым расширениям. Это помогает находить непроверенные участки и регрессии до релиза. Готовые конфигурации Maven приведены в руководстве Quarkus.8 313
В Quarkus 3.37.0 появился новый вход к реляционным данным
Экспериментальное расширение Quarkus Data Hibernate объединяет работу с реляционными базами в одной зависимости. Оно поддерживает расширенные сущности, репозитории с аннотацией
@Repository, блокирующий и неблокирующий режимы, а также запросы на чистом SQL. Реализации репозиториев генерируются при компиляции с проверкой запросов и параметров по модели сущностей.
Для новых приложений команда предлагает начинать с Quarkus Data Hibernate. Реактивная работа требует отдельной зависимости quarkus-hibernate-reactive, поэтому состав приложения остаётся управляемым.
Panache 1 продолжит работать, планов удалять его нет. Инструменты миграции ещё разрабатываются, так что существующие кодовые базы можно переводить без спешки. Расширение войдёт и в Quarkus 4.0; архитектура и ограничения описаны в блоге Quarkus.8 313
Spring и Hibernate: как очищать тестовые данные без @DataJpaTest
Hibernate ORM 6.2 добавил
SchemaManager: его метод truncateMappedObjects() очищает все таблицы, связанные с JPA-сущностями. В интеграционных тестах Spring очистку можно запускать в @BeforeEach, а затем заново добавлять исходные записи через TransactionTemplate.
Так тесты не приходится оборачивать в транзакцию @DataJpaTest. Иначе тестовый EntityManager остаётся доступен после вызова сервисного метода и может инициализировать ленивые прокси, хотя в рабочей среде они уже вызвали бы LazyInitializationException. Часть SQL-операторов также может не выполниться, а целостность базы останется непроверенной.
Очистка в начале теста надёжнее @AfterEach: при сбое или остановке в отладчике завершающий метод может не выполниться. В разборе Vlad Mihalcea есть полный пример с последовательными и параллельными переводами между счетами.8 313
Как Hardwood ускоряет чтение фиксированных списков Parquet
Parquet кодирует координаты и векторные представления как списки переменной длины, даже если размер всегда одинаков. При чтении он разбирает признаки пустых значений и границы записей, выделяет массивы и собирает списки заново. Это примерно втрое медленнее плоской колонки.
Для готовящегося релиза Hardwood реализовали быстрый путь: читатель проверяет, что страница состоит из списков одной длины без пустых значений, и пропускает реконструкцию Dremel. В тесте с ZSTD списки из трёх элементов читались в 1,1 раза быстрее построчно и в 2,5 раза быстрее по колонкам. Для 768 элементов ускорение достигло 3,7 и 2,5 раза соответственно.
В разборе механизма показано, как байтовые шаблоны проверяются пачками и когда включается обычная обработка. Java Vector API оставили возможным следующим шагом, если эта проверка сама станет узким местом.
8 313
Как сборщики мусора JDK связывают память и производительность
JDK предлагает несколько сборщиков мусора с разными характеристиками. При этом у них есть общие архитектурные решения, которые отличают управление памятью в Java от сборки мусора в других языках. Материал объясняет, почему сборщики JDK устроены именно так и как их работа влияет на производительность приложений.
Отдельная тема: связь между объёмом RAM и нагрузкой на CPU бывает неочевидной, поэтому рассматривать эти ресурсы нужно вместе. Такой взгляд помогает обсуждать память Java не только через объём занятой RAM, но и через вычислительную цену выбранного подхода.
В материале Inside.java также разбирают спорный вопрос: действительно ли Java расходует слишком много памяти или другие языки используют её слишком мало. Полезная проверка предпосылок перед сравнением сборщиков мусора и профилей нагрузки.
8 313
Docker Compose с JDK 26: зависимости в контейнерах, Java локально
В примере Maven-приложение остаётся обычным локальным процессом, а Postgres 18 запускается через Docker Compose. Версия базы закреплена в
docker-compose.yml, порт 5433 хоста связан с портом 5432 контейнера, поэтому JDBC подключается к localhost:5433.
Так команда получает одинаковую версию и конфигурацию базы после клонирования репозитория. Контейнер запускается командой docker compose up -d и удаляется через docker compose down, а Java-код можно отлаживать с обычными точками останова без пересборки образа.
В разборе Дэна Веги есть полный пример приложения закладок на JDK 26, Maven и JDBC, структура Compose-файла и команды для логов и консоли PostgreSQL.8 313
Как перевести Dev Services на новый API Quarkus 3.25
В Quarkus 3.25 появился новый API для Dev Services. Старый механизм мог запускать сервисы для всех тестов ещё при обнаружении JUnit: в наборах с разными профилями это приводило к нескольким контейнерам, конфликтам портов и лишним расходам.
Теперь Quarkus подготавливает сервис при сборке, а запускает после аугментации, до старта приложения. Ядро сравнивает конфигурации, переиспользует экземпляры и управляет их жизненным циклом.
Авторам расширений предлагают перейти на
owned() и discovered(), передавать сервис через Startable и убрать статические поля. Пользователям миграция не нужна.
Чеклист и пример кода есть в материале Quarkus.8 313
Hibernate 7: как заменить устаревший
@GenericGenerator
При миграции на Hibernate 7 аннотацию @GenericGenerator предлагают заменить метааннотацией @IdGeneratorType. Она связывает собственную аннотацию поля с классом генератора, после чего Hibernate создаёт идентификатор при сохранении сущности.
В статье Vlad Mihalcea разобраны два прежних сценария. Для идентификаторов TSID, отсортированных по времени, на поле id ставится @Tsid, связанная с TsidGenerator. Для оптимизатора последовательности pooled-lo используется @SequenceOptimizer. Обе готовые реализации есть в Hypersistence Utils.
Для enterprise-кодовой базы это практическая карта миграции: найти применения @GenericGenerator, разделить собственные генераторы и настройки последовательностей, затем перенести каждую группу на соответствующую аннотацию.8 313
Как собрать движок отказоустойчивых сценариев на Java и SQLite
Persistasaurus показывает устройство движка, который сохраняет состояние многошагового Java-сценария. Метод с
@Flow задаёт сценарий, методы с @Step обозначают сохраняемые шаги, а SQLite хранит их параметры, статусы и результаты.
После сбоя сценарий запускают с тем же UUID. Завершённые шаги получают результаты из журнала, а упавший шаг выполняется повторно. Так приложение не дублирует уже успешные операции, например дорогие и недетерминированные обращения к большим языковым моделям.
В разборе Gunnar Morling есть схема журнала и критерий для границ шага: сохранять стоит долгие, дорогие или трудно воспроизводимые операции. Это учебный прототип, а не готовый промышленный движок, но по нему удобно разобрать механику контрольных точек и восстановления Java-сервисов.8 313
Как построить многоуровневую защиту LLM-вызовов в Spring AI 2.0
В Spring Boot 4.1 защиту вызова модели можно собрать из цепочки перехватчиков. Системная инструкция ограничивает темы, а
SafeGuardAdvisor отклоняет запрос до модели по совпадению с заданной подстрокой.
Граница встроенного фильтра: поиск чувствителен к регистру. pass заблокирует вопрос о передаче аргумента, а PASSWORD пройдёт. В примере выходной перехватчик ищет секрет в ответе без учёта регистра и заменяет ответ до возврата клиенту. Входной слой маскирует имя, почту и номер карты до обращения к модели.
Для корпоративной кодовой базы вывод практический: проверяйте запрос и ответ, а SafeGuardAdvisor считайте одним рубежом защиты. В статье Дэна Веги есть код четырёх слоёв и порядок их подключения в Spring AI.8 313
В JDK 27 и 28 ускорили операции Curve25519
С JDK 27 build 14 изменения внутренних структур данных повысили пропускную способность операций на Curve25519: на 49–54% для генерации ключей и согласования по X25519, на 46–49% для генерации ключей, подписи и проверки по Ed25519, на 27–51% для постквантового гибридного обмена X25519MLKEM768.
В JDK 28 build 5 добавили встроенные оптимизации с машинными инструкциями для конкретной архитектуры. На x86_64 они дают ещё 12–20% в зависимости от алгоритма, на AArch64: 7–15%. Приложения получают ускорение через JCE, а обмен ключами TLS 1.3 ещё и через JSSE.
Обе версии пока доступны как ранние сборки. Для миграционного плана их можно проверить на своей архитектуре и нагрузке. Диапазоны и ссылки на тесты приведены в материале Inside Java.
8 313
Как Project Leyden помогает искать задержки запуска Quarkus
Quarkus с Project Leyden переносит загрузку и связывание классов в тренировочный запуск, а затем сохраняет их подготовленное состояние. В статье REST-приложение из
quarkus create app стартует за 130 мс. При старте около 100 мс расход даже в 5 мс уже заметен.
Когда загрузка классов почти исчезла из профиля, проявились другие затраты: рефлексия для проверки возможностей JDK, разбор аннотаций с созданием прокси-объектов и поиск отсутствующих классов или ресурсов. Такой поиск может открыть множество JAR-файлов лишь для ответа «не найдено».
Для enterprise-библиотек вывод практический: проверки совместимости и редко меняющиеся метаданные стоит по возможности обрабатывать при сборке, а не при каждом старте приложения. В разборе в блоге Quarkus это показано на профилях Netty и Hibernate ORM.8 313
Как получить Post и User без загрузки PostDetails в Hibernate
Если PostDetails опциональна, запрос от неё с JOIN FETCH не подходит: запись может отсутствовать, а бизнес-логике нужны только Post и связанный User.
Решение из разбора Vlad Mihalcea: начать JPQL-запрос с Post, присоединить PostDetails по общему идентификатору, затем User и вернуть обе сущности через конструктор Java Record. Если промежуточной записи нет, поле пользователя будет
null.
Hibernate добавляет выбранные сущности в текущий контекст персистентности. Изменение Post поэтому превращается в UPDATE при flush(). Такой приём позволяет не добавлять обратную связь @OneToOne или @OneToMany в родительскую сущность только ради чтения.