Pull to refresh
32K+
60
Spring АйО@spring_aio

Главный по Spring

26
Rating
438
Subscribers
Send message

Тестовые фикстуры: управление зависимостями в Gradle

Level of difficultyEasy
Reading time3 min
Reach and readers9.1K

В многомодульных Gradle-проектах рано или поздно появляются вспомогательные классы для тестов: фабрики тестовых данных, билдеры, хелперы. Такие классы не относятся ни к продакшн-коду, ни к обычным тестам. Логично было бы переиспользовать их сразу в нескольких модулях, но классическая модель Gradle этого не позволяет: тестовые артефакты одного проекта нельзя просто так подключить как зависимость в другом. 

На самом деле Gradle умеет решать эту задачу из коробки без вспомогательных проектов и хитрых конфигураций. Начиная с версии 5.6, тестовые фикстуры стали в Gradle полноценной сущностью первого класса, и весь этот пласт боли можно убрать буквально несколькими строчками в build.gradle.

Плагин java-test-fixtures заводит в модуле отдельный SourceSet, а другие модули подключают эти классы через лаконичный DSL. При публикации Gradle даже собирает отдельный *-test-fixtures.jar для независимых проектов. В статье на примерах показано, как расшарить тестовые хелперы между модулями, избавиться от дублирования и при этом сохранить чистые архитектурные границы. Если вы устали таскать тестовый код из модуля в модуль, то Вам точно пригодится.

Читать далее

Масштабирование Java-систем реального времени

Level of difficultyEasy
Reading time19 min
Reach and readers7.7K

Событийно-ориентированная архитектура красиво выглядит на схеме — пока не встречается с требованиями реального времени.

В переводе от команды Spring АйО разбирается опыт масштабирования Java-платформы контакт-центра: почему локальные кеши начали расходиться, как повторное воспроизведение Kafka-событий почти сделало бесполезным автомасштабирование, откуда взялось получасовое отставание потребителей и почему часть критических путей пришлось вернуть к синхронному взаимодействию.

Без войны с Kafka и без универсальных рецептов — только архитектурные компромиссы, которые становятся видны под рабочей нагрузкой.

Читать далее

Самокорректирующийся структурированный вывод в Spring AI 2.0

Level of difficultyEasy
Reading time9 min
Reach and readers8.7K

Софту всё чаще приходится интегрироваться с LLM. И тут быстро всплывает неприятная деталь: модели хорошо пишут текст, но не всегда стабильно возвращают данные в строгой структуре.

Даже если явно попросить ответ по JSON Schema, модель может добавить пояснение, пропустить поле или вернуть не тот тип. Нативный structured output у части провайдеров есть, но он работает не везде и не одинаково.

В новом переводе от команды Spring АйО разбираем, как в Spring AI 2.0 решается эта проблема.

Читать далее

Reflection замедляет ваш Java-код. Почему?

Level of difficultyEasy
Reading time11 min
Reach and readers9.3K

Сколько раз вы слышали тезис о том, что в Java Reflection тормозит, и лучше его избегать. Насколько это правда?

В новом переводе от команды Spring АйО рассмотрим, почему производительность reflection-а имела проблемы.

Читать далее

В Java нет универсального типа для денег

Level of difficultyEasy
Reading time26 min
Reach and readers16K

double быстрый, но хранит десятичные числа как двоичные приближения: 0.1 + 0.2 дает 0.30000000000000004. BigDecimal точен в десятичной арифметике, но дороже по памяти и CPU.

Выбор зависит от задачи: для метрик и ML хватит double с допуском, для налогов и счетов нужен BigDecimal с явным RoundingMode, для низкой latency - fixed-point на long.

Ошибка не в double или BigDecimal, а в выборе без понимания точности, округления и нагрузки. Подробнее - в новом переводе от команды Spring АйО.

Читать далее

Spring Batch научился работать с MongoDB

Level of difficultyEasy
Reading time8 min
Reach and readers8.8K

Spring Batch - проект в рамках экосистемы Spring Framework, который, как правило не получает должного внимания. Тем не менее, это хорошее решение для Enterprise Batch Processing.

Долгое время Spring Batch требовал SQL-базу для хранения общего состояния, шагов перехода, статусов выполнения и время запусков. Даже если проект жил на MongoDB, рядом часто приходилось держать Postgres или MySQL только ради метаданных.

В Spring Boot 4.1 стало проще: появился spring-boot-starter-batch-data-mongodb. Теперь Spring Batch научился работать с MongoDB.

В статье Josh Long рассказывает про новинки в рамках Spring Batch, в том числе и новую интеграцию с MongoDB, а также работу с GraalVM

Читать далее

Project Valhalla: 10 спустя

Level of difficultyEasy
Reading time19 min
Reach and readers10K

В новом переводе от команды Spring АйО рассмотрим решение старой проблемы в Java: полноценные классы часто слишком дорогие для памяти и процессора.

Пример - массив из миллиона, например, точек Point. Сейчас это обычно не миллион точек подряд, а миллион ссылок на объекты в куче. У каждого объекта есть служебные данные, его нужно создать, потом убрать сборщиком мусора. Плюс процессор постоянно прыгает по памяти, а это медленно.

Project Valhalla добавляет value class. Это обычный на вид класс с полями, конструктором и методами, но без идентичности объекта. JVM сможет хранить такие данные плотнее: например, прямо внутри массива, без отдельного объекта для каждого значения.

JEP 401 планируют включить в JDK 28 как preview. Это еще не финал: value class пока может быть null, а полная поддержка быстрых generics и плотных коллекций появится позже. Но первый рабочий шаг Valhalla уже близко.

Читать далее

Новые возможности Hibernate 7.4

Level of difficultyEasy
Reading time5 min
Reach and readers13K

Hibernate 7.4 исправляет старую проблему с пагинацией и fetch join.

Раньше запрос на первые 10 Order вместе с OrderItem не мог безопасно ограничиться на уровне SQL. Из-за join один заказ превращался в несколько строк, и limit мог обрезать коллекцию. Поэтому Hibernate загружал все подходящие строки, а страницу выбирал уже в памяти. На больших данных это било по памяти и могло закончиться OutOfMemoryException.

Теперь Hibernate сначала выбирает нужные id родительских сущностей во вложенном запросе, а затем загружает для них полные дочерние коллекции. Пагинация остается в БД, данные не режутся.

Еще в 7.4 появились history и audit tables. @Temporal хранит версии строк и позволяет читать сущность на конкретный момент времени. @Audited пишет изменения ADD/MOD/DEL в audit-таблицу без Envers.

Читать далее

Проблема фантомной записи: почему ваша реализация идемпотентности незаметно теряет данные

Level of difficultyEasy
Reading time7 min
Reach and readers10K

В проде бывает так, что одна и та же операция часто повторяется: клиент не дождался ответа и ретраит, балансер порвал соединение, очередь переиграла сообщение. Вспоминаем про идемпотентность - это правило «повтор не должен создавать новый платёж/заказ».

Чтобы отличать повтор от новой операции, используют idempotency key (ключ идемпотентности). Это обычная уникальная строка-идентификатор, которую клиент или апстрим отправляет вместе с запросом (часто в заголовке Idempotency-Key). Сервис сохраняет этот ключ у себя и связывает с результатом операции.

Далее приходит запрос с тем же ключом - сервис не выполняет бизнес-действие второй раз, а дедуплицирует на основе ключа идемпотентности. Но так ли всё просто? Многолетний опыт анализа инцидентов показал, что на практике большое количество систем всё же регулярно допускают дублирования, хотя делали всё по методичке.

В новом переводе от команды Spring АйО рассмотрим не самые очевидные ошибки и то, о чём стоит подумать, при реализации идемпотентного API.

Читать далее

Перевополщение Stable Values в JDK 26

Reading time9 min
Reach and readers9K

В новом переводе от команды Spring АйО рассмотрим ленивую инициализацию в Java , которая почти всегда значит: поле сначала null, потом double-checked locking, volatile, синхронизация. Ошибиться легко, а final не поставить. Итог - код хрупче и JVM хуже делает constant folding.

В JDK 26 (preview, JEP 526) добавили LazyConstant<T>: final поле, рецепт вычисления через Supplier, значение доступно черезget(). Supplier выполнится при первом get и только один раз успешно, даже при гонке потоков. Кроме этого значение помечается как @Stable - JVM может считать его константой и агрессивнее оптимизировать.

Граничные случаи: null нельзя; не сериализуется; исключение из Supplier пробросится и следующая попытка снова пересчитает; equals у LazyConstant - только identity.

Для 1:n есть List.ofLazy и Map.ofLazy: элементы/значения считаются по индексу/ключу по требованию и кэшируются.

Читать далее

Я залез в исходники Claude Code. Фичи, которых нет в документации

Level of difficultyEasy
Reading time16 min
Reach and readers17K

Оказывается, документация Claude Code рассказывает не всё. Стоило только лишь заглянуть в исходники. И вот что можно настроить, но чего нет в доке:

— hooks, которые переписывают команды на лету;
— автоодобрение safe-команд без лишних подтверждений;
— постоянная память агентов между сессиями;
— auto-mode, который понимает описание окружения на обычном английском;
— самообучающиеся циклы памяти и «снов»;
— скрытые поля skills, agents и permissions, которых нет в документации.

И все это работает уже сейчас, а исходники Claude Code лежат у вас в node_modules. Мы собрали все в статью. Там больше конкретики, JSON-конфигов, shell-хуков и примеров, которые можно утащить себе почти без правок.

Читать далее

Java — быстрая. Ваш код может таким не быть

Level of difficultyEasy
Reading time12 min
Reach and readers17K

Есть такие анти‑паттерны, которые выглядят нормально и даже проходят код‑ревью, но тихо убивают производительность в горячих местах: 

- Конкатенация строк в циклах

- String.format() в горячем коде

- Автобоксинг 

и так далее. И каждый подобный пролёт делает приложение чуть медленнее, и в какой-то момент это рискует превратиться в критическую массу, которая больно выстрелит на следующем спайке нагрузки.

Если вы пишете на Java и у вас всё вроде работает, но под нагрузкой сервисы начинают задыхаться, в новом переводе от команды Spring АйО рассмотрим конкретные паттерны, на которые стоит посмотреть.

Читать далее

Соль и перец в безопасности паролей

Level of difficultyEasy
Reading time6 min
Reach and readers13K

Безопасность данных сегодня стала главным приоритетом для любого веб-ресурса. Базовым стандартом защиты учетных записей является хеширование паролей. Этот процесс превращает конфиденциальные символы в необратимый код. Без него утечка базы данных мгновенно скомпрометирует пользователей.

Однако обычного хеширования недостаточно из-за угрозы быстрых хакерских атак. Для защиты разработчики применяют «соль» (salt) — случайные данные, добавляемые к паролю. Минус соли в том, что она хранится рядом с хешем и не спасает от мощного перебора. Тогда на помощь приходит «перец» (pepper), скрытый в коде сервера. Его главная проблема — высокий риск потерять доступ ко всем аккаунтам при компрометации самого секретного ключа.

В новом переводе от команды Spring АйО попробуем разобраться в эволюции методов криптографической защиты. Вы узнаете, как правильно комбинировать эти инструменты для надежной аутентификации.

Читать далее

Эволюция API без боли: ArchUnit, Gradle и правила для библиотек

Level of difficultyEasy
Reading time10 min
Reach and readers11K

В Netflix тысячи Java-репозиториев. Когда в библиотеку вносят изменение, часть пользователей может перестать собираться или начать работать некорректно. Чаще всгео эта проблема возникает потому, что public контракты являются public только для авторов библиотеки, а не для пользователей.

С новом переводе от команды Spring АйО разбираемся, как ребята из Netflix ввели простые метки для API: @Public - можно использовать снаружи, @Experimental - тоже можно, но интерфейс может меняться, @Deprecated - готовится к удалению. Все остальное считается внутренним и использованию извне не подлежит. Но сами аннотации проблему не решают, нужна проверка на масштабе.

Решение - ArchUnit + Nebula ArchRules. 

ArchUnit анализирует скомпилированный байткод, поэтому одинаково работает для Java/Kotlin/Scala и проверяет реальный код на classpath. Команды пишут правила (например: «вне пакета библиотеки нельзя зависеть от ее deprecated/internal API»), публикуют их как отдельный arch-rules JAR, а runner автоматически запускает проверки в репозиториях и делает отчеты с точной строкой нарушения.

Читать далее

Kotlin переходит к деструктурированию по именам

Level of difficultyEasy
Reading time6 min
Reach and readers9.9K

В Kotlin деструктурирование выглядело так: val (name, age) = person. Но компилятор берет значения не по именам, а по позиции component1/component2.

Отсюда проблемы. Если поменяли порядок параметров в data class или сделали age вычисляемым свойством: то та же строка начинает доставать другое поле. Причем иногда код даже скомпилируется, но, конечно, смысл изменится: val (age, name) = person.

И вот теперь Kotlin эксперементально переводит круглые скобки на деструктурирование по имени. Синтаксис будет такой: (val name, val age) = person. И порядок внутри скобок не важен. Переименование явно: (val years = age, val theName = name) = person.

Позиционное же деструктурирование остается, но переезжает в квадратные скобки для Pair/Triple и коллекций: val [x, y] = point.

Разбираемся полностью в новом переводе от команды Spring АйО.

Читать далее

Команда Spring о Spring Framework 7 и Spring Boot 4

Level of difficultyEasy
Reading time11 min
Reach and readers12K

В новом переводе от команды Spring АйО рассмотрим выход Spring Boot 4 и Spring Framework 7. InfoQ взяли интервью у core команды Spring с целью узнать, куда движется самая популярная в Java экосистема.

Spring Boot 4 модуляризировал автоконфигурацию. Теперь при запуске проверяется меньше классов в classpath, а uber-jar будет более компактным: будут подключаться только нужные модули. Параллельно Spring Boot 4 переходит на Jackson 3, но добавлен модуль совместимости с Jackson 2, потому что экосистема ещё догоняет.

Spring Framework 7 тащит core resilience в ядро: RetryTemplate, @Retryable и @ConcurrencyLimit доступны без отдельной зависимости. @Retryable работает и с реактивными типами (через Retry из Project Reactor); для обычных вызовов используется RetryTemplate с политикой retry/backoff. @ConcurrencyLimit помогает ограничивать доступ к ресурсу, что особенно полезно с Virtual Threads.

Читать далее

Поддержка Docker Compose в Spring Boot 3.1

Level of difficultyEasy
Reading time4 min
Reach and readers9.8K

Иногда перед разработчиком встает задача воссоздания некоторого окружения локально. В него часто входят различные компоненты инфраструктуры, такие как:

– PostgreSQL

– Kafka

– RabbitMQ

– Redis

И так далее. Менеджить целый зоопарк таких сервисов локально бывает не очень удобно. К счастью, у команды Spring Boot для вас есть небольшой помошник - Spring Boot Docker Compose.

Комментарий от Михаила Поливахи:

Друзья, хоть на дворе уже Spring Boot 4, мы знаем, что большинство из вас сидит на Spring Boot 3. И мы посчитали очень нужным рассказать о таком Spring Boot инструменте, который, на наш взгляд, делает локальную разработку со Spring Boot намного более приятной.

Читать далее

REST умер? Почему Java-разработчики уходят в GraphQL

Level of difficultyEasy
Reading time10 min
Reach and readers14K

Один экран в приложении, а на бэкенде несколько REST-вызовов, куча эндпоинтов и ответы, где 90% полей не используются. Теряем в скорости, усложняется фронтенд и приходится версионировать контракт, когда меняется формат данных.

GraphQL предлагает другой подход: один API-эндпоинт и запрос, в котором клиент сам указывает, какие поля ему нужны. Это снижает overfetching, уменьшает количество сетевых затрат и упрощает договоренности между фронтом и бэком за счет схемы как явного контракта и живой документации.

В новом переводе от команды Spring АйО разберем, где GraphQL реально помогает: как уйти от разрастания эндпоинтов, как держать контракт синхронизированным и что делать с типичными проблемами производительности и наблюдаемости, когда данные собираются из разных источников.

Читать далее

Самый простой способ устроить утечку памяти в Java

Level of difficultyEasy
Reading time12 min
Reach and readers9.4K

В новом переводе от команды Spring АйО рассмотрим утечки памяти в Java.

Не секрет, что GC освобождает только недостижимые объекты. Утечка в Java начинается там, где объект уже не нужен, но на него все еще есть цепочка ссылок от живого потока.

Симптомы обычно одинаковые: куча растет, GC срабатывает чаще, паузы увеличиваются, финал - java.lang.OutOfMemoryError: Java heap space.

В целом вывод такой, что нужно смотреть график heap в VisualVM/JVisualVM/JConsole, снимать heap dump (jmap), в Eclipse MAT запускать Leak Suspects и проверять цепочки удерживающих ссылок.

Читать далее

Раздувание памяти JDK 17 в контейнерах: разбор инцидента

Level of difficultyEasy
Reading time9 min
Reach and readers13K

В новом переводе от команды Spring АйО разберем тему раздувания памяти в JDK 17. Апгрейд микросервисов с JDK 8 на JDK 17 прошел dev и QA спокойно, но в проде через 2-3 часа все начало падать. Утилизация памяти выросла в 4 раза, контейнеры стали ловить OOMKill и перезапускаться, Uptime SLA просел, массовый инцидент.

Раньше JVM использовала около 50% памяти контейнера и обслуживала ~400 потоков. После релиза стало 95-100% и 1600+ соответственно. 

При этом heap выглядел нормально, около Xmx, а раздувалась нативная память: ~800 MB -> 3,4-3,6 GB. Виноваты несколько эффектов, которые в контейнерах усиливаются: JVM начала создавать намного больше потоков, OS стала выделять JVM гораздо больше, а дефолтный GC в JDK 17 добавил накладные расходы.

Всё это из-за простого бага в JDK, который при миграции утащил за собой весь production.

Читать далее
1
23 ...

Information

Rating
345-th
Works in
Registered
Activity