25698
Все самое полезное для Java-разработчика в одном канале. Список наших каналов: https://t.me/proglibrary/9197 Обратная связь: @proglibrary_feedback_bot По рекламе: @proglib_adv Прайс: @proglib_advertising
🐸 Библиотека джависта
#DevLife
📨 Transactional Outbox c AI
Сценарий: сохранил сущность, опубликовал событие в Kafka, транзакция откатилась — событие уже ушло. Или наоборот: транзакция прошла, Kafka недоступна — событие потеряно.
Outbox Pattern решает это на уровне архитектуры. Промпт:
Ты Senior Java-разработчик. Сгенерируй реализацию Transactional Outbox Pattern для Spring Boot.
Требования:
- Сущность OutboxEvent: id (UUID), aggregateType, aggregateId, eventType,
payload (JSONB), createdAt, processedAt, status (PENDING/PROCESSED/FAILED)
- OutboxEventPublisher: сохраняет событие в той же транзакции что и бизнес-данные
- OutboxPoller: @Scheduled, читает PENDING-события, публикует в Kafka
- SELECT FOR UPDATE SKIP LOCKED при выборке — объясни зачем в комментарии
- @Transactional(propagation = REQUIRES_NEW) на polling-методе
- Flyway-миграция для таблицы
Стек: Java 21, Spring Boot 3.2, Spring Kafka, PostgreSQL, Flyway
Верни код сущности, репозитория, сервисов, SQL-миграцию, конфиг Kafka.
✌🏻 У нас две новости — хорошая и плохая!
Хорошая: Ваших знаний, скорее всего, хватит, чтобы собрать рабочую демку AI-агента в Colab. 🫡
Плохая: Вы вряд ли выведете его в прод, не обанкротившись на токенах и не слив базу. 🤯
Для защиты от таких сценариев мы полностью пересобрали курс «Разработка AI-агентов». Теперь внутри плотная работа с экономикой ресурсов, дебаг через time-travel в LangGraph, извлечение данных из кривых сканов для RAG и комплаенс по 152-ФЗ.
Если всё ещё сомневаетесь, послушайте голосовое от спикера курса Влада Прошинского, где он объясняет, как правильно тестировать агентов перед релизом.
🎁 Паттерн Decorator
Decorator — структурный паттерн, который добавляет объектам новое поведение, оборачивая их в объекты-обёртки. Альтернатива наследованию, когда комбинаций поведения много и они меняются в рантайме.
Использование
🔹 Когда нужно добавить поведение объекту, не меняя его класс и не трогая остальные объекты.
🔹 Когда наследование порождает взрывной рост классов из-за комбинаций поведений.
🔹 Когда поведение нужно добавлять и убирать динамически в рантайме.
Преимущества
1️⃣ Гибкость комбинирования поведений
Каждый декоратор делает одно дело. Нужно кеширование + логирование + метрики? Оборачиваете в три слоя в любом порядке. Не нужны метрики — просто не добавляете этот слой.
2️⃣ Единая ответственность
Кеширование живёт в одном классе, логирование — в другом. Каждый декоратор легко читать, тестировать и заменять независимо.
3️⃣ Прозрачность для клиента
Декоратор реализует тот же интерфейс, что и оригинал. Клиентский код не знает, с чем работает — с оригиналом или с обёрткой.
⚠️ Порядок декораторов имеет значение. Метрики снаружи кеша видят кеш-хиты корректно. Метрики внутри — не видят их вообще.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
🖥 JDK 21 или 25, что выбрать новичку
Вышла Java 25, которую все хотят попробовать. Но ставить ли её или взять проверенную Java 21 LTS?
В этом гайде — пошаговая установка Java на Windows с картинками, разбор различий между версиями, настройка JAVA_HOME и PATH.
Ориентирован для начинающих разработчиков, изучающих Java
🔗 Читайте в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
🐸 Библиотека джависта
#DevLife
👑 IntelliJ IDEA: Evaluate Expression
Открывается через Run → Evaluate Expression или Alt + F8 (Option + F8 на macOS).
🔹 Что это вообще такое
Небольшое окно с полем ввода, в котором можно написать любое Java-выражение и мгновенно получить результат. Код выполняется в контексте текущего фрейма — видны все локальные переменные, this, поля класса.
🔹 Примеры из реальной жизни
▪️ Вызов метода на живом объекте
userService.findById(42L)
order.getItems().stream()
.anyMatch(i -> i.getPrice().compareTo(BigDecimal.ZERO) < 0)
user.setRole(Role.ADMIN)
objectMapper.writeValueAsString(response)
😱 Если ваш продукт не умеет отдавать данные в формате, понятном AI-агенту, то вас просто не существует
Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности.
Как адаптировать продукт и не исчезнуть из выдачи:
— интегрировать MCP и A2A-взаимодействие, чтобы агенты могли вас читать;
— научиться контролировать стоимость (лимиты, кэш, роутинг между моделями);
— настроить AgentOps: трейсинг, логирование и отлов регрессий.
Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях.
Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше.
Зафиксировать цену и начать деплоить агентов без слива бюджета 👈
🐸 Библиотека джависта
#DevLife
😮 Топ-вакансий для джавистов за неделю
Java Developer - офис (Санкт-Петербург)
Middle (Middle+) Backend Developer - офис (Санкт-Петербург)
Middle/Senior Java Developer - офис (Москва)
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🐸 Библиотека джависта
#DevLife
🧵 StampedLock: когда ReentrantReadWriteLock уже не справляется
Если знаком с ReentrantReadWriteLock, то знаешь идею: много читателей одновременно, но запись эксклюзивна. Звучит разумно, но у этой модели есть фундаментальная проблема: читатели блокируют писателей.
Поток, который хочет писать, ждёт пока все читатели закончат. При высокой read-нагрузке писатель может ждать очень долго. StampedLock решает именно это.
🔵 Три режима, не два
ReentrantReadWriteLock даёт два режима — read и write. StampedLock добавляет третий — optimistic read.
StampedLock lock = new StampedLock();
// обычный read lock
long stamp = lock.readLock();
try {
// читаем
} finally {
lock.unlockRead(stamp);
}
// write lock
long stamp = lock.writeLock();
try {
// пишем
} finally {
lock.unlockWrite(stamp);
}
long stamp = lock.tryOptimisticRead();
// читаем данные без блокировки вообще
int value = this.value;
if (!lock.validate(stamp)) {
// кто-то писал пока мы читали — перечитываем под реальным локом
stamp = lock.readLock();
try {
value = this.value;
} finally {
lock.unlockRead(stamp);
}
}
👑 IntelliJ IDEA: продвинутый дебаг
Представь, что есть цикл на 10 000 элементов, и баг воспроизводится только на одном конкретном объекте. Без Conditional Breakpoints придется жать F8 вручную сотни раз. А с ними дебаггер сам остановится в нужный момент.
🔹 Как включить
Кликни правой кнопкой на кружок брейкпоинта → появится поле Condition. Введите любое булево Java-выражение. Всё, дебаггер будет останавливаться только когда оно true.
🔹 Примеры из реальной жизни
▪️ Фильтрация по ID
user.getId() == 42
request.getUrl().contains("/admin")order.getItems() == null
i == 999
✔️ Java-тест: кэш убивает прод под нагрузкой
Метрики норм, тесты зелёные, при пике трафика — БД ложится 👇
📦 Задание — code review
Сервис отдаёт профили пользователей. Для ускорения добавили кэш на 5 минут.
@Service
@RequiredArgsConstructor
public class UserProfileService {
private final UserRepository userRepository;
private final RedisTemplate<String, UserProfile> redisTemplate;
private static final Duration TTL = Duration.ofMinutes(5);
public UserProfile getProfile(Long userId) {
String key = "profile:" + userId;
UserProfile cached = redisTemplate.opsForValue().get(key);
if (cached != null) {
return cached;
}
UserProfile profile = userRepository.findById(userId)
.map(UserProfile::from)
.orElseThrow(UserNotFoundException::new);
redisTemplate.opsForValue().set(key, profile, TTL);
return profile;
}
}
🌐 Зачем нужен CDN и как он работает
Когда пользователь из Сиднея открывает ваш сайт, его запрос летит на сервер в Германии и обратно. Это ~300 мс только на «дорогу» — и это для каждого изображения, шрифта, JS-файла.
CDN (Content Delivery Network / Сеть доставки контента) решает эту проблему в лоб: вместо одного сервера — тысячи точек по всему миру. Пользователь получает файлы с ближайшей к нему ноды, а не с вашего origin-сервера.
🔹 Origin и Edge
В архитектуре с CDN появляются два новых понятия:
— Origin Server (Главный сервер): это ваш настоящий сервер, где крутится Spring Boot, лежит база данных и хранятся оригиналы всех файлов (например, в Amazon S3).
— Edge Servers (Граничные серверы / Точки присутствия - PoP): это тысячи серверов CDN-провайдера (например, Cloudflare или Akamai), раскиданные по всему земному шару: в Сиднее, Токио, Нью-Йорке, Лондоне, Москве.
🔹 Как работает кэш
Первый запрос к конкретному файлу всё равно идёт до origin. CDN его скачивает, кэширует у себя и отдаёт пользователю. Все последующие запросы на тот же файл edge-сервер обрабатывает сам, не трогая ваш бэкенд. Это называется cache hit.
🔹 Что кладем в CDN
CDN идеально подходит для статического контента:
— Картинки, видео, аудио.
— Скомпилированные файлы JavaScript и CSS.
— Шрифты.
CDN не подходит для динамического контента:
— Корзина товаров.
— Приватные данные пользователя.
— (Запросы к API /api/v1/users/me должны идти напрямую на ваш сервер, минуя кэш CDN).
🔹 Защита от DDoS
Современные CDN (тот же Cloudflare) - это не просто кэш. Это гигантский щит.
Если хакеры решат «положить» ваш сайт и отправят миллион запросов в секунду, этот удар примут на себя серверы CDN. Их пропускная способность измеряется терабитами. Они отфильтруют «мусорный» трафик, и ваш маленький Origin-сервер даже не заметит атаки.
🔹 Побочные эффекты
— Ускорение: пользователи получают тяжелый контент мгновенно, потому что скачивают его из своего же города.
— Экономия: ваш главный сервер больше не тратит процессорное время и трафик на отдачу терабайтов картинок. Вы платите за сервера меньше.
— Безопасность: CDN скрывает реальный IP-адрес вашего сервера и защищает от DDoS-атак.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
✔️ Java-тест: 1 запрос в коде = 10 000 запросов в БД
Код чистый, тесты быстрые, на реальных данных — pg_stat_activity в огне 👇
📦 Задание — code review
Ручка возвращает список заказов с информацией о товарах. Работает корректно, но DBA прибежал с графиком: каждый вызов делает тысячи запросов к БД.
@Entity
public class Order {
@Id
private Long id;
private Long userId;
private LocalDateTime createdAt;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "order")
private List<OrderItem> items;
}
@Entity
public class OrderItem {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
private Integer quantity;
}
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderRepository orderRepository;
@GetMapping("/orders")
public List<OrderDto> getOrders(@RequestParam Long userId) {
List<Order> orders = orderRepository.findByUserId(userId);
return orders.stream()
.map(order -> new OrderDto(
order.getId(),
order.getItems().stream()
.map(item -> new ItemDto(
item.getProduct().getName(),
item.getQuantity()
))
.toList()
))
.toList();
}
}
👩💻 Разработка на Java требует глубокого понимания не только языка, но и принципов работы JVM, многопоточности и современных фреймворков.
🎯 Курс «Java Developer. Professional» — это структурированное обучение для разработчиков, которые хотят выйти на новый уровень, освоить актуальный стек технологий и уверенно претендовать на позиции уровня Middle+.
Вы получите 96 часов практической работы, на живых вебинарах разберете ключевые аспекты работы JVM, научитесь строить эффективные многопоточные приложения, освоите Spring WebFlux, Kafka, реактивный Postgres и Kubernetes.
📚Программа OTUS постоянно обновляется, соответствуя требованиям рынка, а диплом ценится работодателями.
➡️ Пройдите вступительное тестирование и присоединяйтесь к группе: https://clc.to/0LN5fQ
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
😮 Топ-вакансий для джавистов за неделю
Java-разработчик Middle - от 200 000 до 250 000 ₽ - гибрид (Новосибирск)
Java-разработчик - от 280 000 ₽ - удалёнка
Tech Lead (Java / Spark) - 400 000 ₽ - офис (Москва)
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🐸 Библиотека джависта
#DevLife
🧵 GC: как выбрать сборщик мусора и не пожалеть
Выбирал ли ты GC хоть раз осознанно? Часто запустил приложение — работает, и ладно. Но когда начинаются проблемы с латентностью или throughput, первый вопрос от SRE: «А какой у вас GC?».
🔹 Разберём что выбрать и почему.
Все GC балансируют между двумя вещами:
▪️ Throughput — сколько полезной работы делает приложение за единицу времени
▪️ Latency — насколько долго приложение паузится на GC
Идеального нет. Выбор всегда зависит от профиля нагрузки.
🔹 Serial и Parallel — если латентность не важна
-XX:+UseSerialGC / -XX:+UseParallelGC
-XX:+UseG1GC
bash-XX:MaxGCPauseMillis=200 # целевое время паузы
-XX:+UseZGC / -XX:+UseShenandoahGC
bash-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=20m
✔️ Java-тест: утечка в фильтре
Memory leak, который живёт неделями и не воспроизводится локально 👇
📦 Задание — code review
Написали фильтр для аудита запросов. В продакшне через несколько дней — OutOfMemoryError.
@Component
public class AuditFilter implements Filter {
private static final ThreadLocal<AuditContext> CONTEXT =
new ThreadLocal<>();
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
AuditContext ctx = new AuditContext(
((HttpServletRequest) request).getRequestURI(),
System.currentTimeMillis()
);
CONTEXT.set(ctx);
try {
chain.doFilter(request, response);
} finally {
auditLog(CONTEXT.get());
}
}
public static AuditContext current() {
return CONTEXT.get();
}
private void auditLog(AuditContext ctx) {
// пишем в БД...
}
}
🐸Библиотека джависта
#DevLife
♻️ Redis-кеш с AI
@Cacheable над методом поставить несложно. Сложнее объяснить тимлиду почему прод лежит, когда Redis недоступен — а CacheErrorHandler никто не написал.
Промпт, который закрывает этот пробел сразу:
Ты Senior Java-разработчик. Сгенерируй модуль кеширования для Spring Boot 3.x с Redis.
Требования:
- RedisCacheConfiguration с GenericJackson2JsonRedisSerializer
- CacheManager с раздельными TTL для разных кешей (RedisCacheManagerBuilder)
- 2 сервиса с @Cacheable, @CachePut, @CacheEvict — с комментарием когда что применять
- Кастомный CacheErrorHandler (деградация без исключения при недоступном Redis)
- application.yml конфиг
- Тест: @SpringBootTest + Testcontainers Redis
Стек: Java 21, Spring Boot 3.2, Spring Data Redis, Testcontainers 1.19
@EnableCaching — только в отдельном @Configuration, не в Application-классе.
Верни код классов, yml, тест.
❓ В чём разница между Statement и PreparedStatement?
— Statement используется для выполнения простых SQL-запросов без параметров. Он формирует запрос как строку и каждый раз компилирует его заново, что может быть медленно и небезопасно.
— PreparedStatement предварительно компилируется базой данных и позволяет задавать параметры через плейсхолдеры. Что повышает производительность при многократном выполнении одного запроса и защищает от SQL-инъекций (данные не конкатенируются со строкой запроса, а подставляются корректно).
Поэтому в реальных проектах почти всегда используют PreparedStatement.
🐸 Библиотека собеса по Java
#core
🔨 Паттерн Builder
Builder — порождающий паттерн, который разделяет конструирование сложного объекта и его представление. Позволяет создавать объекты пошагово и получать разные результаты, используя одинаковый процесс построения.
Использование
🔹 Когда конструктор принимает много параметров — особенно если часть из них опциональна.
🔹 Когда порядок шагов построения важен или требует валидации перед созданием.
🔹 Когда нужно создавать разные представления одного и того же объекта.
Преимущества
1️⃣ Читаемость и явное намерение
Конструктор с 7 параметрами — это загадка. Builder с именованными шагами — спецификация. Читая вызов, вы сразу понимаете, что создаётся и почему.
2️⃣ Безопасная валидация
Вся проверка параметров сосредоточена в методе build(). Объект либо создаётся корректным, либо не создаётся вообще. Нет промежуточных невалидных состояний.
3️⃣ Иммутабельность
Builder накапливает параметры, build() создаёт финальный неизменяемый объект. Это удобно в многопоточном коде и делает объекты предсказуемыми.
4️⃣ Поддержка опциональных параметров без перегрузок
Вместо пяти перегруженных конструкторов — один Builder. Указываете только то, что нужно, остальное берёт дефолт.
⚠️ Lombok даёт @Builder за одну аннотацию — но понимать механику всё равно стоит.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
😁 Развернем холиварчик
К статье на Хабре «Я два месяца платил 300к человеку, который тихо скармливал мои задачи в ChatGPT» уже почти 900 комментов.
Прочитайте, давайте тоже обсудим 💬
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
Почитали тут свежий отчёт по рынку ИИ-ускорителей в РФ: оказывается, 54% компаний тормозят внедрение ИИ исключительно из-за конских цен на инфраструктуру.
Ну, то есть написать пет-проект с вызовом API это задача на вечер, а вот запустить агента в продакшн так, чтобы он не сжёг бюджет отдела за неделю — суровая инженерия.
По сути, сейчас мало уметь собирать RAG. Нужно считать токены, настраивать time-travel дебаг в LangGraph и уметь роутить запросы на лету. Всё это мы учли в обновлённом курсе по разработке AI-агентов, где акцент сделан именно на AgentOps и жёсткий контроль ресурсов.
Также в программе:
— оценка качества, трейсинг и защита от деградации пайплайнов;
— мультиагентные паттерны и интеграция по протоколу MCP;
— локальный деплой Open Source под 152-ФЗ (когда данные нельзя выносить наружу).
Кажется, это единственный адекватный roadmap по переходу от блокнотов к enterprise-решениям.
Прямо сейчас можно урвать курс с увесистой скидкой (49 000 ₽ 62 990 ₽ за базовый тариф и 99 000 ₽ 124 990 ₽ за продвинутый трек), но стоит поторопиться — на потоке осталось всего 5 мест.
👉 Зафиксировать цену и начать собирать агентов, за которых не стыдно в проде
🔐 Security-модуль за 5 минут с AI
Каждый раз одно и то же: новый проект, пишешь JWT с нуля, лезешь в старые репозитории за шаблоном, получаешь deprecated код на Spring Security 5.
Можно иначе — сформулировал промпт так, чтобы AI сразу выдал то, что не придётся переписывать.
Ты Senior Java-разработчик. Сгенерируй production-ready модуль безопасности для Spring Boot 3.x.
Требования:
- JWT (access + refresh токены), фильтр OncePerRequestFilter
- SecurityFilterChain: csrf off, session stateless
- UserDetailsService через JPA-репозиторий
- Пакеты: security/config, security/filter, security/service
- Обработка AuthenticationException и AccessDeniedException — отдельные handler-классы
- Никакого WebSecurityConfigurerAdapter
Стек: Java 21, Spring Boot 3.2, Spring Security 6, JJWT 0.12.x
Верни полный код всех классов с import и package.