javaproglib | Unsorted

Telegram-канал javaproglib - Библиотека джависта | Java, Spring, Maven, Hibernate

25698

Все самое полезное для Java-разработчика в одном канале. Список наших каналов: https://t.me/proglibrary/9197 Обратная связь: @proglibrary_feedback_bot По рекламе: @proglib_adv Прайс: @proglib_advertising

Subscribe to a channel

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

Как правильно определять границы сервисов в микросервисной архитектуре?

Один из недооценённых скиллов в разработке — это умение провести правильную границу между сервисами. Большинство «распределённых монолитов», которые мы встречаем в продакшене, рождаются именно здесь.

Разобрали тему — держи шпаргалку 👇

🔹 Что такое Service Boundary

Это контракт на три вещи:

— за что сервис отвечает;
— какими данными он владеет;
— как он общается с соседями.

Представь компанию: HR не лезет в финансы, а склад не занимается зарплатами. Так же должны работать твои сервисы.

🔹 4 принципа, которые работают

1. Business Capability First

Режь по бизнес-функциям, а не по техническим слоям. OrderService, PaymentService, UserService, потому что именно так бизнес думает о системе.

2. Single Responsibility

Один сервис — одна ответственность. Если в описании сервиса есть союз и, это уже тревожный звоночек 🚨

3. Data Ownership

У каждого сервиса своя БД. Без исключений. Shared database = shared pain.

4. Loose Coupling

Только API, никакого прямого доступа к чужим таблицам.

🔹 Классический антипаттерн

// ❌ Бизнес-логика смешана в одном сервисе
@Service
public class BadOrderService {
public String processOrderAndPayment(int id) {
String order = orderRepository.findById(id)
.orElse("Order not found");
String paymentStatus = "Payment Successful"; // 🚨 чужая ответственность
return order + " | " + paymentStatus;
}
}


Выглядит безобидно, пока не нужно масштабировать платежи отдельно, сменить платёжного провайдера или добавить retry-логику только для оплаты. Тут и начнутся реальные проблемы.

🔹 Советы из практики

Начни с монолита. Не дроби систему заранее. Сначала пойми домен, потом режь по швам.
Следи за chatty communication. Если сервис делает 10 вызовов к соседям на каждый запрос, граница явно проведена не там.
Изучи DDD. Bounded Context из Domain-Driven Design это лучший инструмент для поиска правильных границ. Инвестиция окупается быстро

💬 Делимся в комментах страшными историями god-сервисов.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#CoreJava

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

Сохраняйте шпаргалку по HTTP кодам

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)?

Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или выдает мусор? Приглашаем на открытый вебинар, где разберем реальную боль внедрения LLM-агентов и научимся делать так, чтобы «всё работало».

🗓️ Когда: 7 мая в 19:00 МСК
⏱️ Формат: 60 минут мяса + 30 минут ответов на ваши вопросы

🧑🏻‍💻 Кто вещает: Эмиль Сатаев — Backend Platform Developer (8+ лет в разработке). Человек, который своими руками внедряет LLM и агентные системы в реальные коммерческие сервисы.

🎁 Главный бонус для онлайна:
Только участникам прямого эфира подарим уникальный промокод на скидку 10.000 ₽ на большой курс AgentOps.

👉 Занять место на вебинаре

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

📦 Java медленно превращается в Haskell

Records, Sealed Classes, Pattern Matching — это уже не просто фичи. Это Data-Oriented Programming: иммутабельные данные отдельно, логика отдельно.

Для одних это долгожданная эволюция. Для других тихое убийство ООП, которому в Java 30 лет.

💬 Используешь DOP в продакшне? И что в целом думаешь об изменениях в языке?

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🕯 TimSort в Java

Arrays.sort(Object[]) и Collections.sort() используют TimSort — алгоритм, разработанный Тимом Петерсом для Python в 2002 году и портированный в Java 7. Для примитивов используется dual-pivot quicksort, но для объектов — только TimSort, и причина этого выбора нетривиальна.

🔹 Почему не quicksort для объектов

Quicksort не стабилен — одинаковые элементы могут поменяться местами. Для примитивов это безразлично: два одинаковых int неразличимы. Для объектов же критично: Comparator может считать два объекта равными по одному критерию, но они остаются разными объектами. Нестабильная сортировка ломает составные компараторы и пользовательские ожидания.

Merge sort стабилен, но требует O(n) дополнительной памяти и не использует частичную упорядоченность входных данных.

🔹 Как работает TimSort

TimSort строится на наблюдении: реальные данные редко полностью случайны. Массивы часто содержат уже упорядоченные подпоследовательности — runs.

Алгоритм:

1. Проходит по массиву, находя естественные runs — уже отсортированные (возрастающие или убывающие) подпоследовательности. Убывающие разворачиваются на месте.

2. Если run короче минимального порога (minRun, вычисляется от размера массива, обычно 32-64 элемента) — расширяется insertion sort'ом. Insertion sort эффективен на почти отсортированных коротких последовательностях.

3. Runs помещаются в стек и сливаются попарно через merge sort. Merge происходит не сразу — алгоритм поддерживает инвариант на стеке runs для гарантии O(n log n) в худшем случае.

🔹 Galloping mode

При слиянии двух runs TimSort переключается в режим gallopping если обнаруживает что элементы из одного run идут длинными сериями подряд. Вместо поэлементного сравнения — бинарный поиск: ищет где именно заканчивается серия из первого run. Это даёт O(n) на уже отсортированных данных вместо O(n log n).

Порог переключения в gallopping — MIN_GALLOP = 7. Если 7 раз подряд «выиграл» один run — переключаемся. Порог динамически адаптируется: если gallopping оказывается неэффективным, порог растёт.

🔹 Сложность

→ Лучший случай (уже отсортированный массив): O(n) — один run, ничего сливать не нужно.
→ Средний и худший: O(n log n).
→ Память: O(n) в худшем случае, но на практике меньше — временный буфер для merge не всегда равен половине массива.

🔹 Практическое следствие

Если данные поступают уже частично отсортированными — TimSort это эксплуатирует автоматически. Повторная сортировка почти отсортированного массива значительно дешевле первичной сортировки случайных данных. Это важно для пайплайнов где данные сортируются инкрементально или приходят из источника с естественным порядком.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#CoreJava

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🗓 Выброси Date и забудь Calendar

Если ты работал с java.util.Date или Calendar, то сталкивался с этими проблемами. Мутабельные объекты, месяцы с нуля, запутанный API. В Java 8 появился java.time (JSR-310), и это то, что должно было быть с самого начала.

🔹 Instant — source of truth

Instant now = Instant.now(); // 2024-01-15T19:00:00Z

// Из Unix timestamp
Instant fromSeconds = Instant.ofEpochSecond(1705341600L);

// Получить timestamp
long epochMilli = now.toEpochMilli();

// Арифметика
Instant later = now.plusSeconds(3600); // +1 час

// Наносекундная точность (не то что Date с миллисекундами)
long nanos = now.getNano();


Храни в БД именно Instant. Никакой TZ-зависимости и никаких сюрпризов.

🔹 LocalDateTime, когда TZ не нужна

LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15T19:00:00");

// ✅ Юзер ввёл дату без TZ
// ✅ Бизнес-логика без мультирегиональности
// ❌ Хранение в БД — используй Instant
// ❌ API-ответы — неоднозначно без TZ


🔹 ZonedDateTime для пользователей

ZonedDateTime ny = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

// Конвертация между TZ — один и тот же момент времени
ZonedDateTime london = ny.withZoneSameInstant(ZoneId.of("Europe/London"));


DST обрабатывается автоматически:
// 10 марта 2:30 AM не существует (переход на летнее время)
LocalDateTime nonExistent = LocalDateTime.of(2024, 3, 10, 2, 30);
ZonedDateTime adjusted = nonExistent.atZone(ZoneId.of("America/New_York"));
// → автоматически станет 3:30 AM EDT


🔹 ZonedDateTime vs OffsetDateTime

// ZonedDateTime — знает правила DST, для будущих дат
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));

// OffsetDateTime — просто смещение, без DST. Для прошлых событий и API
OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.ofHours(-5));


🔹 DateTimeFormatter для форматирования и парсинга

LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);

// Predefined
dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // "2024-01-15T19:00:00"
dt.format(DateTimeFormatter.BASIC_ISO_DATE); // "20240115"

// Custom
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
dt.format(fmt); // "2024-01-15 19:00:00"

// Парсинг с обработкой ошибок
public static Optional<LocalDateTime> parse(String s) {
try {
return Optional.of(LocalDateTime.parse(s, fmt));
} catch (DateTimeParseException e) {
return Optional.empty();
}
}


🔹 Шпаргалка по токенам

yyyy → 2024      MM → 01      dd → 15
HH → 19 (24h) hh → 07 (12h) mm → 00
ss → 00 SSS → 123 a → PM
z → EST Z → -0500 VV → America/New_York


🔹 Duration vs Period


// Duration — точный временной интервал
Duration duration = Duration.ofHours(24); // ровно 86400 секунд

// Period — календарный интервал
Period period = Period.ofDays(1); // 1 день (может быть 23 или 25 ч. при DST!)

// Оба работают с LocalDateTime, но семантика разная:
dt.plus(Duration.ofHours(24)); // +86400 сек
dt.plus(Period.ofDays(1)); // +1 календарный день


🔹 Миграция с легаси

// Date → Instant
Instant instant = oldDate.toInstant();

// Instant → Date
Date date = Date.from(instant);

// Date → LocalDateTime
LocalDateTime ldt = oldDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();


══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

😮 Топ-вакансий для джавистов за неделю

Junior+ Java backend developer — удалёнка

Java-разработчик — от 290 000 ₽ —гибрид (Москва)

Senior Java Backend Developer — 200 000 – 400 000 ₽ — удалёнка/Гибрид (Ставрополь)

➡️ Еще больше топовых вакансий — в нашем канале Java jobs

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🗓️ Уже через пару часов стартует вебинар!

Тема:

Как эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токены


Ждем вас сегодня в 19:00 по московскому времени. Не пропустите начало, будет много практики!

👉 Успей занять место

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

📋 Паттерн Command (Команда)

Command — поведенческий паттерн, который превращает запрос в самостоятельный объект. Этот объект содержит всю информацию о запросе: что делать, с какими параметрами и как это отменить.

Использование

🔹 Когда нужно откладывать выполнение операции или ставить её в очередь.
🔹 Когда требуется undo/redo — история операций.
🔹 Когда нужен аудит: кто, что и когда изменил.
🔹 Когда операции должны быть идемпотентными и безопасными для повтора при сбое.

Преимущества


1️⃣ Undo/Redo из коробки

Каждая команда знает, как себя отменить. Стек команд — готовая история изменений. Так работают все текстовые редакторы и графические инструменты.

2️⃣ Очереди и отложенное выполнение

Команды сериализуются и отправляются в Kafka или RabbitMQ. Воркеры их обрабатывают независимо. Если команда идемпотентна — безопасно повторить при сбое.

3️⃣ Полный audit log

Сохраняете команды в БД — получаете историю всех действий с параметрами. Это основа Event Sourcing: состояние системы восстанавливается воспроизведением команд.

4️⃣ Декомпозиция сложных операций

Макрокоманда объединяет несколько команд. Транзакционное выполнение, откат при ошибке — всё строится поверх простых команд.

🤖 Осталось 4 места на курс по ИИ-агентам. Набор закрывается 30 апреля.
🔗 Успеть на обучение

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#CoreJava

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🔥 База по ИИ-агентам от научного сотрудника Сколтеха и НИУ ВШЭ

Знакомьтесь, Екатерина Трофимова. Кандидат компьютерных наук, ресерчер в Центре ИИ Сколтеха и лаборатории LAMBDA. Она объединяет глубокую академическую экспертизу и практику: знает, как ИИ-системы устроены «под капотом» и как встроить их в реальные проекты (в т.ч. для Т-банка).

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

🛠 Стек и фреймворки:

DSPy — алгоритмическая оптимизация промптов (вместо ручного подбора слов).

Semantic Kernel и LangMem — инструменты для управления сессионной и долгосрочной памятью.

MCP (Model Context Protocol) — новый стандарт от Anthropic для подключения агентов к вашим БД и локальным файлам.

📖 Документация, которую нужно знать:

Anthropic Prompt Caching — как кэшировать контекст и радикально резать косты на API.

OpenAI Agents SDK / Cookbook — лучшие практики работы с памятью.

Augment — платформа для оптимизации работы ИИ-агентов и контроля токенов.

🔬 Хардкорные статьи и препринты (на выходные):

Lost in the Middle — почему LLM «слепнут» на длинных текстах и забывают середину контекста.

How Do Coding Agents Spend Your Money? — куда улетает бюджет при работе автономных кодинг-агентов.

MemGPT — архитектура операционной системы для LLM с иллюзией бесконечной памяти.

InjecAgent / AgentSentry — всё о безопасности и защите агентов от инъекций в промпты.

Екатерина Трофимова — один из ключевых экспертов нашего курса AgentOps. На своих лекциях она детально разбирает, как проектировать инструменты для агентов, как агент принимает решения о вызове инструментов и какие ограничения возникают в реальном проде

🎁 Акция в честь старта продаж!

Прямо сейчас при покупке Инженерного трека вы получаете полный доступ к материалам курса «Разработка ИИ-агентов» в подарок.

👉 Забрать 2 курса по цене 1 и начать обучение

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

😮 Топ-вакансий для джавистов за неделю

Java-разработчик (GitFlic, гибрид) — от 200 000 ₽ — гибрид (Москва)

Java разработчик — 330 000 ₽ — гибрид/Удалёнка (Москве, Санкт-Петербург, Екатеринбург)

Senior Java Engineer (JavaSE, algorithms, optimization) — от 5 000 $ — удалёнка

➡️ Еще больше топовых вакансий — в нашем канале Java jobs

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🎤 Ваши знания по ИИ-агентам + наша аудитория в 1 млн человек = профит

Мы в Proglib активно качаем тему ИИ-агентов. Если вы в теме, то у нас есть предложение 👇

Что с нас?

- Огромный охват: пропиарим ваши соцсети и продукты на 1 000 000+ айтишников.
- Личный бренд: станете узнаваемым экспертом в самой горячей нише 2026 года.
- Никакой рутины: наши редакторы сами упакуют ваши мысли в крутые посты.

Что с вас?

Любой экспертный контент по ИИ-агентам: кейсы из прода, шпаргалки, статьи, наработки по стеку (LangGraph, CrewAI, AutoGen и др.) или просто мысли по архитектуре.

👉 Стать экспертом и заявить о себе

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

😮 Топ-вакансий для джавистов за неделю

Junior Java Developer — удалёнка — Expert Soft

Java-разработчик — от 300 тыс. руб — Локация: РФ / часовой пояс МСК

Team Lead разработки (Java) — удалёнка — АЭРО

➡️ Еще больше топовых вакансий — в нашем канале Java jobs

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

☕️ Магия jcmd

Запустите jcmd <pid> Thread.print, и вы получите полный thread dump живого JVM-процесса — без kill -3, без рестарта, без агентов.

🔹 Зачем это нужно

— Полный дамп всех потоков с трассировками прямо на живом проде;
— Работает с любым JDK-процессом: Spring Boot, Quarkus, Kafka Streams;
— Один бинарник закрывает heap dump, GC-статистику, профилирование и диагностику;
— Не требует JMX, агентов или открытых портов — только PID.

🔹 Как использовать

— Список всех JVM-процессов и их PID:

jcmd

— Все доступные команды для конкретного процесса:
jcmd <pid> help

— Thread dump (дедлоки, зависшие потоки):
jcmd <pid> Thread.print

— Heap dump на диск:
jcmd <pid> GC.heap_dump /tmp/heap.hprof

— Статистика GC в реальном времени:
jcmd <pid> GC.heap_info

— Запустить GC вручную (осторожно на проде):
jcmd <pid> GC.run

— Статистика классов по памяти:
jcmd <pid> GC.class_histogram


jcmd <pid> GC.class_histogram — первое, что стоит запустить при подозрении на утечку памяти: сразу видно, каких объектов неожиданно много и сколько они весят.

⚠️ Некоторые команды требуют флага -XX:+UnlockDiagnosticVMOptions при запуске JVM — иначе получите Exception: No such command. Если команда недоступна, проверьте jcmd <pid> help — там только то, что реально работает для вашего процесса прямо сейчас.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

✔️ Java-тест: кэш, который врёт

Метод возвращает устаревшие данные. Иногда и только на нескольких потоках. Воспроизвести локально — нереально 👇

📦 Задание — code review

Команда добавила простой in-memory кэш для тяжёлых вычислений. На одном потоке работает идеально. На проде с нагрузкой — иногда возвращает старый результат или null.

@Component
public class PricingCache {

private final Map<String, BigDecimal> cache = new HashMap<>();
private final PricingEngine pricingEngine;

public PricingCache(PricingEngine pricingEngine) {
this.pricingEngine = pricingEngine;
}

public BigDecimal getPrice(String productId) {
if (cache.containsKey(productId)) {
return cache.get(productId);
}
BigDecimal price = pricingEngine.calculate(productId);
cache.put(productId, price);
return price;
}

public void invalidate(String productId) {
cache.remove(productId);
}

public void invalidateAll() {
cache.clear();
}
}


▪️ Объясни

— В чём проблема в коде
— Как переписать getPrice верно

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🔥 4 привычки кодеров

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

но, я собрал 4 привычки адептов «чистого кода», (которые обычно все практикуют) 🤡

• Бесконечный рефакторинг рабочего кода.
Кажется, что так ты делаешь продукт лучше. Итог: жестко падаешь в перфекционизм. Переписываешь функцию по три раза, а бизнес ждет релиз. Закрываешь вкладку и в голове абсолютная пустота, время потрачено, а новых фичей ноль.

• Упарывание в сложную архитектуру

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

• Душные споры на ревью
Неплохо, но как итог: ты пишешь полотна текста и тратишь часы на поиск глупой придирки к стилю, потому что банально фокус сместился с реальной задачи на эго.

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

Проблема в том, что ни один из этих путей не дает самого главного - скорости и проверки гипотез. Реальному рынку плевать на твой идеальный код за 3 дня. Бизнес предпочтет код от ИИ-агента за 5 минут, который уже завтра начнет приносить деньги.

Хочешь обкатанный на нас лично и 100х учениках метод, как перестать кодить руками и начать делегировать задачи автономным системам?

👉 Заходи сюда, но у нас осталось всего 4 места, набор идет до завтрашнего дня.

P. S. Если интересно еще что-нибудь почитать от меня, то заходите в «Азбуку Айтишника», там я рассказываю об айти-базе, также у меня там есть бесплатный гайд на 15 глав по ии-агентам

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🧵 Как починить мертвый ThreadLocal в пуле потоков

Если положить RequestId / userId / traceId в ThreadLocal и передать задачу в ExecutorService в итоге значение пропадёт. InheritableThreadLocal помогает только при явном создании потока, но не при переиспользовании из пула.

Alibaba решили это ещё в 2013 году, а библиотека до сих пор активно поддерживается → TransmittableThreadLocal (TTL).

🔹 Подключается:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.5</version>
</dependency>


🔹 Используется как обычный ThreadLocal, только умнее:
TransmittableThreadLocal<String> traceId = new TransmittableThreadLocal<>();
traceId.set("req-123");

ExecutorService pool = TtlExecutors.getTtlExecutorService(
Executors.newFixedThreadPool(4)
);

pool.submit(() -> {
// "req-123" — доступен здесь, в потоке из пула
System.out.println(traceId.get());
});


🔹 Три способа интеграции

→ Обернуть Runnable/Callable — TtlRunnable.get(task)
→ Обернуть пул — TtlExecutors.getTtlExecutorService(pool)
→ Java Agent — вообще без изменений в коде: -javaagent:transmittable-thread-local.jar

Агентовый режим особенно полезен, когда нужно прозрачно встроить TTL в легаси-проект или сторонний фреймворк — он патчит JDK-классы пулов на уровне байткода.

0 зависимостей. Работает с виртуальными потоками (Project Loom). Поддерживает кастомный TtlCopier для глубокого копирования значений при передаче в дочерний поток.

Актуально везде, где есть distributed tracing, MDC, tenant isolation или любой per-request контекст в многопоточке.

⚠️ README встретит иероглифами, не пугайся, английская версия лежит в README-EN.md.

🔗 Репозиторий на GitHub

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

☕️ Магия JVM Flags

Запустите своё приложение с -XX:+HeapDumpOnOutOfMemoryError, и когда (не «если») приложение упадёт с OOM, у вас будет дамп памяти.

🔹 Зачем это нужно

— При падении с OutOfMemoryError JVM автоматически сохраняет снапшот всей кучи в .hprof-файл.
— Без него вы знаете лишь факт смерти процесса. С ним — кто именно убил.
— Особенно ценно в контейнерах и CI/CD: процесс умер, лог ротировался, а дамп остался.
— Работает с любым анализатором: Eclipse MAT, IntelliJ Profiler, VisualVM, YourKit.

🔹 Как использовать

— Базовый запуск (дамп рядом с процессом):

java -XX:+HeapDumpOnOutOfMemoryError -jar app.jar

— Задать путь явно (обязательно в проде):
java -XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/dumps/app.hprof \
-jar app.jar

— В Docker нужно монтировать папку наружу, иначе дамп умрёт вместе с контейнером:
-v /host/dumps:/var/dumps

— Руками с живого процесса без рестарта:
jcmd <pid> GC.heap_dump /tmp/live.hprof


🔥 Пока разбираетесь в дебаге JVM — параллельно можно освоить ИИ-агентов. 4 места до 30 апреля.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

💬 Обратная связь

Коллеги, предлагаю актуализировать базу годных ресурсов по Java помимо нашего канала.

✔️ Присылайте в комменты:

— Блоги и статьи
— Telegram-каналы
— YouTube-каналы и подкасты
— Репозитории
— Доклады

Что НЕ ищем

Курсы "java с нуля за месяц", базовые туториалы и переводы официальной документации.

💬 Закидывайте в комменты ваши любимые источники. Для работы, для учёбы, для повседневного чтения.

🐸 Библиотека джависта

#DevLife

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🔧 @Async и ThreadLocal: ловушка, которую не видно в коде

При использовании @Async Spring создаёт новый поток из пула для выполнения метода. Если в основном потоке вы храните данные в ThreadLocal (например, контекст пользователя, tenant ID или trace-информацию) — в асинхронном методе они будут недоступны.

Классическая ловушка:

// Основной поток — кладём данные
UserContext.set(currentUser);

// Вызов @Async метода — данные уже не там
asyncService.processOrder(orderId);


🔹 Решение

▪️ Создать кастомный Executor с передачей контекста через TaskDecorator:
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(runnable -> {
User user = UserContext.get(); // захватываем из текущего потока
return () -> {
try {
UserContext.set(user); // передаём в новый поток
runnable.run();
} finally {
UserContext.clear(); // обязательно чистим
}
};
});
executor.setCorePoolSize(4);
executor.setMaxPoolSize(10);
executor.initialize();
return executor;
}


▪️ Использовать @Async("asyncExecutor") с явным указанием бина:
@Async("asyncExecutor")
public CompletableFuture<Void> processOrder(Long orderId) {
// UserContext.get() теперь вернёт правильного пользователя
}


Без finally { UserContext.clear() } — утечка контекста гарантирована: потоки из пула переиспользуются, и следующий запрос получит чужие данные.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

⚙️ Compressed OOPs

На 64-битной JVM каждая ссылка на объект — это 64-битный указатель. При большом количестве объектов это заметно увеличивает потребление памяти и снижает эффективность кеша: меньше ссылок помещается в cache line. Compressed OOPs (Ordinary Object Pointers) — механизм, который решает эту проблему, но с нетривиальными последствиями при масштабировании heap.

🔹 Механика


JVM выравнивает объекты по 8 байт. Значит, три младших бита любого указателя всегда равны нулю и их можно не хранить. Если сдвинуть 32-битное значение влево на 3 бита, получим 35 бит адресного пространства — 32GB. Именно поэтому compressed oops работают при heap до 32GB: 32-битная "сжатая" ссылка декодируется в реальный 64-битный адрес сдвигом.

реальный адрес = сжатая_ссылка << 3


При heap ≤ 4GB сдвиг не нужен — просто zero-based, ссылка используется напрямую как смещение от адреса 0.

🔹 Пороговые значения


До 4GB heap: нулевое смещение, нет сдвига. Самый быстрый вариант.
4GB — 32GB: сдвиг на 3 бита, смещение ненулевое.
Выше 32GB: compressed oops отключаются, все ссылки становятся 64-битными.

Здесь ловушка. Если поднять heap с 28GB до 33GB — потребление памяти может вырасти не на 5GB, а значительно больше. Все ссылки удваиваются в размере: с 4 до 8 байт. На приложении с десятками миллионов объектов это легко даёт +20-30% к реальному потреблению.

🔹 Как проверить что включено


java -XX:+PrintFlagsFinal -version | grep UseCompressedOops


Или в логах GC при старте с -Xlog:gc+heap=info:
Heap address: 0x00000006c0000000, size: 28672 MB, Compressed Oops mode: Non-zero based


"Zero based" — heap ≤ 4GB, оптимально.
"Non-zero based" — 4-32GB, compressed oops работают но со сдвигом.
Если строки нет и ссылки 8 байт — compressed oops выключены.

🔹 Compressed Class Pointers

Помимо ссылок на объекты, в заголовке каждого объекта есть ссылка на klass (метаданные класса). Она тоже сжимается отдельным механизмом — Compressed Class Pointers, отдельное 32-битное пространство (Metaspace). Управляется -XX:CompressedClassSpaceSize, по умолчанию 1GB.

🔹 Практический вывод

Граница в 32GB — критическая при планировании capacity. Стандартная рекомендация: если нужно чуть больше 32GB, рассмотреть heap в 26-30GB с compressed oops вместо 33GB без них. Реальная эффективная ёмкость может оказаться выше за счёт лучшей утилизации кеша процессора и меньшего давления на GC.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#CoreJava

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

🗓 В следующий вторник (28.04) в 19:00 встречаемся в онлайне.

Тема:

Как эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токены


В кружке Кирилл рассказал, какие именно подходы будем разбирать.

👉 Занять место на вебинаре

Читать полностью…

Библиотека джависта | Java, Spring, Maven, Hibernate

Сохраняйте шпаргалку по спрингу

Собрали шпаргалку по Spring для тех, кто только начинает.

Карта экосистемы, главные аннотации и стартеры, типичные ошибки новичков всего на двух страницах.

══════ Навигация ══════
ВакансииЗадачиСобесы

🐸 Библиотека джависта

#Enterprise

Читать полностью…
Subscribe to a channel