Чашечка Java
8.38K subscribers
3.91K photos
13 videos
56 files
6.37K links
Лучшие материалы по Java на русском и английском

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels
Download Telegram
Как перевести Dev Services на новый API Quarkus 3.25

В Quarkus 3.25 появился новый API для Dev Services. Старый механизм мог запускать сервисы для всех тестов ещё при обнаружении JUnit: в наборах с разными профилями это приводило к нескольким контейнерам, конфликтам портов и лишним расходам.

Теперь Quarkus подготавливает сервис при сборке, а запускает после аугментации, до старта приложения. Ядро сравнивает конфигурации, переиспользует экземпляры и управляет их жизненным циклом.

Авторам расширений предлагают перейти на owned() и discovered(), передавать сервис через Startable и убрать статические поля. Пользователям миграция не нужна.

Чеклист и пример кода есть в материале Quarkus.
1
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.
Как сборщики мусора JDK связывают память и производительность

JDK предлагает несколько сборщиков мусора с разными характеристиками. При этом у них есть общие архитектурные решения, которые отличают управление памятью в Java от сборки мусора в других языках. Материал объясняет, почему сборщики JDK устроены именно так и как их работа влияет на производительность приложений.

Отдельная тема: связь между объёмом RAM и нагрузкой на CPU бывает неочевидной, поэтому рассматривать эти ресурсы нужно вместе. Такой взгляд помогает обсуждать память Java не только через объём занятой RAM, но и через вычислительную цену выбранного подхода.

В материале Inside.java также разбирают спорный вопрос: действительно ли Java расходует слишком много памяти или другие языки используют её слишком мало. Полезная проверка предпосылок перед сравнением сборщиков мусора и профилей нагрузки.
👍2
Как Hardwood ускоряет чтение фиксированных списков Parquet

Parquet кодирует координаты и векторные представления как списки переменной длины, даже если размер всегда одинаков. При чтении он разбирает признаки пустых значений и границы записей, выделяет массивы и собирает списки заново. Это примерно втрое медленнее плоской колонки.

Для готовящегося релиза Hardwood реализовали быстрый путь: читатель проверяет, что страница состоит из списков одной длины без пустых значений, и пропускает реконструкцию Dremel. В тесте с ZSTD списки из трёх элементов читались в 1,1 раза быстрее построчно и в 2,5 раза быстрее по колонкам. Для 768 элементов ускорение достигло 3,7 и 2,5 раза соответственно.

В разборе механизма показано, как байтовые шаблоны проверяются пачками и когда включается обычная обработка. Java Vector API оставили возможным следующим шагом, если эта проверка сама станет узким местом.
👍1
Spring и Hibernate: как очищать тестовые данные без @DataJpaTest

Hibernate ORM 6.2 добавил SchemaManager: его метод truncateMappedObjects() очищает все таблицы, связанные с JPA-сущностями. В интеграционных тестах Spring очистку можно запускать в @BeforeEach, а затем заново добавлять исходные записи через TransactionTemplate.

Так тесты не приходится оборачивать в транзакцию @DataJpaTest. Иначе тестовый EntityManager остаётся доступен после вызова сервисного метода и может инициализировать ленивые прокси, хотя в рабочей среде они уже вызвали бы LazyInitializationException. Часть SQL-операторов также может не выполниться, а целостность базы останется непроверенной.

Очистка в начале теста надёжнее @AfterEach: при сбое или остановке в отладчике завершающий метод может не выполниться. В разборе Vlad Mihalcea есть полный пример с последовательными и параллельными переводами между счетами.
В Quarkus 3.37.0 появился новый вход к реляционным данным

Экспериментальное расширение Quarkus Data Hibernate объединяет работу с реляционными базами в одной зависимости. Оно поддерживает расширенные сущности, репозитории с аннотацией @Repository, блокирующий и неблокирующий режимы, а также запросы на чистом SQL. Реализации репозиториев генерируются при компиляции с проверкой запросов и параметров по модели сущностей.

Для новых приложений команда предлагает начинать с Quarkus Data Hibernate. Реактивная работа требует отдельной зависимости quarkus-hibernate-reactive, поэтому состав приложения остаётся управляемым.

Panache 1 продолжит работать, планов удалять его нет. Инструменты миграции ещё разрабатываются, так что существующие кодовые базы можно переводить без спешки. Расширение войдёт и в Quarkus 4.0; архитектура и ограничения описаны в блоге Quarkus.
1👍1🔥1🤣1
Quarkus 3.31.2: как измерить покрытие runtime-модулей расширений

До версии 3.31.2 расширение quarkus-jacoco учитывало код из @QuarkusTest, но не покрытие runtime-модулей в QuarkusUnitTest. Именно такие тесты обычно составляют большинство в расширениях. Причина в сборке: Quarkus применяет офлайн-инструментирование JaCoCo к архивам приложения, а runtime-модуль расширения обычно к ним не относится.

Теперь артефакты для инструментирования можно явно указать через свойства group-id и artifact-id. Для одного расширения конфигурация добавляется в deployment-модуль, после чего отчёт создаётся автоматически.

Для многомодульного проекта статья показывает, как собирать данные всех тестов в общий файл и строить единый отчёт по зависимым расширениям. Это помогает находить непроверенные участки и регрессии до релиза. Готовые конфигурации Maven приведены в руководстве Quarkus.
🤣1
Как профилировать Java-приложения с JDK Flight Recorder

JDK Flight Recorder (JFR) встроен в OpenJDK и записывает события JVM с небольшими накладными расходами. Его можно использовать для постоянного наблюдения за приложением, а собранную телеметрию разбирать при снижении производительности или сбоях в продакшене.

Материал показывает, как начать работу с JFR, записать данные и перейти к их анализу. Отдельные сценарии посвящены поиску узких мест, утечек памяти и проблем с потоками. Для долгоживущих Java-сервисов это способ исследовать поведение JVM на данных с работающего приложения.

Практические сценарии и демонстрации собраны в материале Inside.java.
😁1🤔1
Как Spring AI 2.0 исправляет структурированный вывод по JSON Schema

Обычный entity(TalkSubmission.class) строит схему из Java-типа и преобразует ответ модели в объект. Если небольшая локальная модель пропустит поле или вернёт недопустимый null, запрос завершится ошибкой 500.

Новый validateSchema(...) сверяет JSON со схемой. При ошибке Spring AI передаёт модели причину и повторяет вызов, по умолчанию до трёх раз. Режим выключен по умолчанию, поэтому существующие вызовы entity после обновления не меняют поведение.

В статье Dan Vega показан пример на Spring Boot с Anthropic и Ollama, а также настройка журнала повторных попыток. Для миграции проверку можно включать точечно там, где нестабильный JSON уже приводит к ошибкам.
👏1
Quarkus 3.29: что изменилось в тестах CDI-компонентов

QuarkusComponentTest запускает не всё приложение, а только CDI-контейнер и сервис конфигурации. Тестируемый бин остаётся реальным, а отсутствующие зависимости автоматически заменяются моками Mockito. Их можно внедрить через @InjectMock и настроить в тестовом методе.

В Quarkus 3.29 переработали загрузку классов. Расширение теперь поддерживает преобразование байткода, упрощённую инъекцию через конструктор, final-классы и методы. Новый SPI позволяет подключать логику до сборки и после запуска контейнера. Интеграция с quarkus-panache-mock добавила компонентные тесты для Panache-сущностей.

В обзоре Quarkus также разобраны жизненный цикл контейнера, автоматический выбор тестируемых компонентов и изменения версий 3.13 и 3.21.
🤔1
Как показать вызовы инструментов в интерфейсе на Spring AI 2.0

Spring AI 2.0 вынес цикл вызова инструментов из реализаций отдельных моделей в цепочку советников ChatClient. Теперь его можно обернуть собственным советником, увидеть промежуточные события и показать пользователю, какой метод выполняется до появления ответа модели.

В примере наблюдающий советник ставится перед ToolCallingAdvisor и получает события начала и завершения каждого вызова. Контроллер передаёт их в браузер через серверный поток событий вместе с ответом модели. Память диалога сохраняет контекст между запросами, поэтому следующий вопрос может ссылаться на предыдущий.

В разборе есть рабочий проект на Spring Boot 4.1: инструменты с @Tool, потоковый контроллер и советник для отслеживания вызовов. Подход пригодится, если интерфейсу корпоративного ИИ-сервиса нужна наблюдаемость без изменений внутри модели.
Value-классы в JDK 28: где JVM убирает аллокации, а где возвращает их

JEP 401 вошёл в JDK 28 как предварительная возможность. Отказ от идентичности позволяет JVM хранить поля без ссылок и раскладывать компоненты по регистрам или стеку, но ускорение не гарантировано.

Неизменяемые поля JVM может хранить плоско, а для изменяемых выбирает ссылку, чтобы потоки не увидели значение из частей разных записей. JIT-компилятор C2 способен убрать создание value record в цикле, но стирание типов и виртуальный вызов могут вернуть объект и аллокацию.

Перед миграцией проверьте горячие участки и переходы между представлениями: три таких случая разобраны в статье Value Classes Still Need Compiler Sympathy.
Почему ref = null обычно не помогает сборщику мусора JVM

Локальная ссылка в стеке потока остаётся корнем GC, пока её фрейм активен. После выхода из метода сборщик её не обходит, поэтому ref = null перед возвратом обычно ничего не меняет.

Сборщик копирует достижимые объекты в другой пул, а прежний затем использует заново. Он сохраняет всё, до чего может добраться от корней, а не удаляет мусор по одному объекту.

Редкое исключение возникает, когда узлы LinkedList лежат в разных поколениях памяти: разрыв связи с обработанной частью иногда сокращает удержание. Но рост памяти требует искать ошибку жизненного цикла: растущую статическую коллекцию, кеш без вытеснения или слушатель без отписки. Разбор стека и достижимости помогает отличить утечку от лишнего присваивания.