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

🖥 Паттерны ООП c примерами

Многие из нас знают паттерны «по названиям». Но можешь ли объяснить, чем AbstractFactory отличается от FactoryMethod? Или когда Prototype — не оверинжиниринг, а реальное решение?

На Хабре вышла первая часть добротного разбора порождающих паттернов с примерами. Без воды, с живыми примерами на Kafka vs RabbitMQ, Spring @Component, Lombok @Builder.

👉 Читать на Хабре

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

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

#CoreJava

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

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

🏭 Паттерн Factory Method

Factory Method — это порождающий паттерн, который предоставляет интерфейс для создания объектов в суперклассе, но позволяет подклассам изменять тип создаваемых объектов.

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

🔹 Когда тип создаваемого объекта зависит от контекста или конфигурации.
🔹 Когда нужно расширять систему новыми продуктами без правки существующего кода.
🔹 Когда создание объекта — это не просто new, а логика с условиями.

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

1️⃣ Ослабление связи между кодом и конкретными классами

При прямом вызове new вы жёстко привязаны к конкретному классу. Если его нужно заменить — придётся найти и исправить все точки создания. Фабрика убирает эту зависимость: код работает через интерфейс, конкретная реализация подставляется в одном месте.

2️⃣ Централизованное управление созданием объектов

Фабрика может содержать нетривиальную логику:

▪️ Выбор нужного класса в зависимости от условий.
▪️ Управление жизненным циклом объекта.
▪️ Применение Singleton или Object Pool внутри фабрики.

3️⃣ Расширяемость без правки существующего кода

Новый тип продукта — новый подкласс. Основной код не трогаете. Это и есть принцип Open/Closed в действии.

4️⃣ Упрощение тестирования

Фабрику можно подменить в тестах — подсунуть mock-реализацию. Это чище, чем патчить конструктор или использовать статические методы.

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

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

#CoreJava

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

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

Какие уровни изоляции транзакций существуют?

Существует 4 основных уровня изоляции транзакций, каждый из которых определяет степень видимости данных, изменённых в одной транзакции, для других транзакций:

🔹 READ UNCOMMITTED

Наименьший уровень изоляции. Другие транзакции могут читать изменения, которые ещё не были зафиксированы (не коммитнуты). Это может привести к грязным чтениям.

🔹 READ COMMITTED

Транзакция видит только те изменения, которые были зафиксированы другими транзакциями. Это предотвращает грязные чтения, но допускает неповторяемые чтения.

🔹 REPEATABLE READ

Гарантирует, что данные, считанные в рамках одной транзакции, не изменятся до её завершения (не допускаются неповторяемые чтения). Однако, могут возникать фантомные чтения.

🔹 SERIALIZABLE

Все транзакции выполняются последовательно, как если бы они были выполнены по очереди.

Реализуется через блокировки (Lock-based): БД ставит range locks — блокирует не только существующие строки, но и диапазоны, куда могут вставиться новые. Это устраняет все виды аномалий, но может значительно снизить производительность.


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

#concurrency

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

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

У «Библиотеки программиста» появился резервный канал в мессенджере MAX

Он нужен исключительно для связи с теми, кто не может следить за обновлениями здесь из-за трудностей с доступом. Поэтому, если вы видите это сообщение, распространите его среди жильцов вашего ЖЭКа.

Контент в MAX будет дублировать телеграмный — основной нашей площадкой был и остаётся Telegram. Надеемся, это временная мера.

Подписаться на «Библиотеку программиста» в MAX

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

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

🔧 Micrometer: кастомные метрики которые реально полезны в production

Стандартные метрики Spring Boot (JVM, HTTP, datasource) — это база. Бизнес-метрики и метрики производительности конкретных операций пишутся вручную.

🔹 Решение

▪️ Базовые типы метрик

@Service
public class OrderMetrics {

private final Counter ordersCreated;
private final Counter ordersFailed;
private final Timer orderProcessingTime;
private final DistributionSummary orderAmountSummary;
private final AtomicInteger activeOrders;

public OrderMetrics(MeterRegistry registry) {
this.ordersCreated = Counter.builder("orders.created")
.description("Total orders created")
.tag("environment", "production")
.register(registry);

this.ordersFailed = Counter.builder("orders.failed")
.description("Total failed orders")
.register(registry);

this.orderProcessingTime = Timer.builder("orders.processing.time")
.description("Order processing duration")
.publishPercentiles(0.5, 0.95, 0.99)
.publishPercentileHistogram()
.sla(Duration.ofMillis(200), Duration.ofSeconds(1))
.register(registry);

this.orderAmountSummary = DistributionSummary.builder("orders.amount")
.description("Order amounts distribution")
.baseUnit("USD")
.publishPercentiles(0.5, 0.95)
.register(registry);

this.activeOrders = registry.gauge("orders.active",
new AtomicInteger(0));
}

public Order processOrder(OrderRequest request) {
activeOrders.incrementAndGet();
return orderProcessingTime.record(() -> {
try {
Order order = doProcess(request);
ordersCreated.increment();
orderAmountSummary.record(order.getAmount().doubleValue());
return order;
} catch (Exception e) {
ordersFailed.increment();
throw e;
} finally {
activeOrders.decrementAndGet();
}
});
}
}


▪️ Тег-стратегия для разрезания метрик


Timer.builder("external.api.calls")
.tag("service", "payment-gateway")
.tag("operation", "charge")
.tag("status", result.isSuccess() ? "success" : "failure")
.register(registry)
.record(duration);


В Grafana это даёт возможность делать rate(external_api_calls_total{status="failure"}[5m]) и смотреть ошибки по сервисам отдельно.

▪️ application.yml для Prometheus

management:
endpoints:
web:
exposure:
include: health,info,prometheus,metrics
metrics:
distribution:
percentiles-histogram:
http.server.requests: true
slo:
http.server.requests: 50ms,200ms,500ms,1s
tags:
application: ${spring.application.name}
environment: ${APP_ENV:local}


publishPercentileHistogram() — ключевая настройка для Timer. Без неё Prometheus получает только count/sum и заранее вычисленные перцентили. С ней — полную гистограмму, из которой Prometheus сам считает перцентили через histogram_quantile().

Это важно при агрегации метрик с нескольких инстансов: заранее вычисленные перцентили нельзя корректно агрегировать, гистограммы — можно.

⚠️ Каждая уникальная комбинация тегов создаёт отдельный time series в Prometheus. Теги с высокой кардинальностью (userId, orderId, IP-адрес) убивают Prometheus. Теги должны иметь конечное и небольшое множество значений.

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

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

#Enterprise

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

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

👑 Магия IntelliJ IDEA

IntelliJ IDEA может помочь с созданием тестов. С помощью Ctrl + Shift + T можно сгенерировать структуру тестов для классов и методов.

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

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

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

— Поместите курсор на класс или метод, для которого нужен тест.
— Нажмите Ctrl + Shift + T (на Windows/Linux) или Cmd + Shift + T (на macOS).
— Выберите, какой тестовый фреймворк использовать (JUnit, TestNG и т.д.), и IDEA предложит создать тестовый класс с нужной структурой.

IDE автоматически создаст тестовый класс с методами для проверки каждого (или выбранного) публичного метода.

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

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

#CoreJava

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

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

🖥 Тренажёр администрирования Linux-серверов

SadServers — это симулятор сисадмина и DevOps, где вы подключаетесь к реальному виртуальному серверу по SSH и чините настоящие проблемы, а не тестовые кейсы.

Как это выглядит

— Выдают сломанный сервер с конкретной задачей
— Заходите по SSH, находите причину и фиксите
— Есть таймер, не успели — сервер отключается

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

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

#Enterprise

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

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

🔧 Spring Retry: повторные попытки с backoff без ручных циклов

Retry-логика руками — источник багов. Неправильный backoff создаёт thundering herd. Spring Retry решает это декларативно.

🔹 Решение

▪️ Зависимость

<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>


▪️ Включение и базовое использование

@Configuration
@EnableRetry
public class RetryConfig { }

@Service
public class ExternalApiService {

@Retryable(
retryFor = {IOException.class, HttpServerErrorException.class},
noRetryFor = {HttpClientErrorException.class}, // 4xx не ретраим
maxAttempts = 4,
backoff = @Backoff(
delay = 1000,
multiplier = 2,
maxDelay = 10000,
random = true // jitter для предотвращения thundering herd
)
)
public ApiResponse callExternalApi(ApiRequest request) {
return restClient.post()
.uri("/api/endpoint")
.body(request)
.retrieve()
.body(ApiResponse.class);
}

@Recover
public ApiResponse recover(IOException e, ApiRequest request) {
log.error("All retry attempts exhausted for request: {}", request.getId(), e);
// fallback логика или выброс бизнес-исключения
throw new ExternalServiceUnavailableException(request.getId(), e);
}
}


▪️ Программная конфигурация для сложных случаев

@Bean
public RetryTemplate retryTemplate() {
return RetryTemplate.builder()
.maxAttempts(5)
.exponentialBackoff(1000, 2, 30000)
.retryOn(IOException.class)
.withListener(new RetryListenerSupport() {
@Override
public <T, E extends Throwable> void onError(RetryContext ctx,
RetryCallback<T, E> cb,
Throwable t) {
log.warn("Retry attempt {} failed: {}",
ctx.getRetryCount(), t.getMessage());
}
})
.build();
}


▪️ Интеграция с Circuit Breaker


@CircuitBreaker(name = "externalApi", fallbackMethod = "circuitFallback")
@Retryable(retryFor = IOException.class, maxAttempts = 3)
public ApiResponse callWithProtection(ApiRequest request) {
return callExternalApi(request);
}


Retry отрабатывает до Circuit Breaker. Ошибки после всех попыток засчитываются как один сбой в Circuit Breaker — корректное поведение.

random = true в @Backoff добавляет jitter — случайное смещение задержки. Без jitter все инстансы приложения, получившие ошибку одновременно, будут ретраить синхронно, создавая пики нагрузки на восстанавливающийся сервис. Jitter разбивает пики.

⚠️ Ретраить нужно только идемпотентные операции. POST с созданием ресурса без идемпотентного ключа при ретрае создаст дубликаты. Либо добавить Idempotency-Key заголовок, либо не ретраить.

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

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

#Enterprise

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

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

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

#DevLife

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

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

Объясните happens-before отношение в Java Memory Model?

happens-before — это гарантированный порядок между операциями, который определяет, что эффект одной операции виден другой. Если операция A happens-before операции B, то все изменения, сделанные в A, будут видны к моменту B.

Примеры гарантий happens-before: запись в volatile поле и последующее чтение того же поля; блокировки synchronized; Thread.start() и Thread.join().

Без гарантии happens-before два потока могут видеть неверные или устаревшие значения: один поток записал в поле, другой не увидит это изменение.

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

#concurrency

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

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

🔥 Java наконец-то избавляется от «налога на объект»

28 МБ для хранения миллиона точек вместо честных 8 — вот цена идентичности каждого объекта в JVM. Project Valhalla это исправляет.

Value Classes — и данные лежат в памяти плоско, как примитивы. Никаких заголовков, никакого pointer chasing, GC доволен.

🔗 Подробно с цифрами в статье

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

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

🔍 BeanDefinition Pipeline

Spring ApplicationContext при старте проходит через чётко определённую последовательность фаз. Понимание этой последовательности объясняет, почему одни расширения работают, а другие нет, и почему порядок объявления бинов иногда имеет значение.

Фазы загрузки контекста

1️⃣ Загрузка BeanDefinition'ов

Контекст читает конфигурацию и строит реестр BeanDefinition. На этом этапе объекты ещё не создаются. BeanDefinition — это метаданные: класс, scope, зависимости, lazy/eager, init/destroy методы.

2️⃣ BeanFactoryPostProcessor

После того как все BeanDefinition загружены, но до создания каких-либо бинов, вызываются BeanFactoryPostProcessor. Они получают доступ к ConfigurableListableBeanFactory и могут модифицировать, добавлять или удалять BeanDefinition.

Самый известный пример — PropertySourcesPlaceholderConfigurer. Он резолвит ${...} плейсхолдеры в BeanDefinition прямо на этом этапе. Именно поэтому @Value("${some.property}") работает — к моменту создания бина значение уже подставлено в метаданные.

ConfigurationClassPostProcessor — ещё один критический BeanFactoryPostProcessor. Он обрабатывает @Configuration классы, @ComponentScan, @Import, регистрирует дополнительные BeanDefinition. Без него Spring Boot не работал бы.

⚠️ BeanFactoryPostProcessor сам является бином, но Spring создаёт его раньше остальных отдельным путём. Если BeanFactoryPostProcessor зависит от другого бина через @Autowired — этот бин будет создан раньше срока, до фазы BeanPostProcessor. Это ведёт к тому что аспекты и другие пост-процессоры не применяются к нему. Spring даже выводит предупреждение в лог в таких случаях.

3️⃣ Создание экземпляра и инициализация

Для каждого eager singleton:
— Создание инстанса через конструктор или фабричный метод.
— Внедрение зависимостей (setter injection, field injection).
— Вызов BeanPostProcessor.postProcessBeforeInitialization.
— Вызов init-метода (@PostConstruct → InitializingBean.afterPropertiesSet() → initMethod)
— Вызов BeanPostProcessor.postProcessAfterInitialization.

BeanPostProcessor — именно здесь работает Spring AOP. AbstractAutoProxyCreator реализует BeanPostProcessor и в postProcessAfterInitialization оборачивает бин в прокси если нужно.

4️⃣ SmartInitializingSingleton

После инициализации всех singleton-бинов Spring вызывает afterSingletonsInstantiated() на каждом бине, реализующем этот интерфейс. Полезно, когда нужно выполнить логику гарантированно после того, как все синглтоны готовы — в отличие от @PostConstruct, который срабатывает до завершения инициализации остальных бинов.

5️⃣ Публикация события ContextRefreshedEvent

После того как все бины готовы. ApplicationListener на этот ивент — стандартный способ выполнить логику после полного старта контекста.

🔹 Порядок BeanPostProcessor'ов

Порядок определяется через Ordered или PriorityOrdered. PriorityOrdered применяется раньше Ordered, Ordered раньше остальных. Внутри одного уровня по getOrder().

Это важно когда несколько BeanPostProcessor обрабатывают один бин: AOP-прокси, валидация, кастомный мониторинг. Неправильный порядок может привести к тому что один пост-процессор получит прокси вместо оригинального объекта или наоборот.

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

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

#CoreJava

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

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

Нужно создать внутренний сервис без лишней сложности и с полным контролем над архитектурой? 

Используйте NocoBase — самую расширяемую no-code платформу с поддержкой ИИ  💻

Даже если вы только знакомитесь с low-code, у вас получится развернуть свое бизнес-приложение, потому что этому мы обучаем в Академии NocoBase.

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

🔜 Видеоролики будем публиковать в наших социальных сетях, а первые анонсы в телеграм-канале @nocobase_ru. Подписывайтесь, чтобы не пропустить обновления!

#АкадемияNocoBase #nocobase #обучение #lowcode #nocode #opensource #ai #it

Реклама. ООО «МАТРЕШКА МАРКЕТ»
ИНН 7814825148
erid: CQH36pWzJqV7gyq7DAkzuSnAf
JWCn7RSc2ctNk97ef47K5

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

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

🌐 Как настроить Spring Cloud Gateway

Spring Cloud Gateway — это API Gateway поверх Project Reactor. Маршрутизация запросов, балансировка нагрузки, rate limiting, аутентификация.

Реактивный, non-blocking, легко расширяемый через фильтры.

1️⃣ Добавляем зависимости

Добавьте spring-cloud-starter-gateway — это вытащит Reactor Netty как сервер. Важно: НЕ добавляйте spring-boot-starter-web, они несовместимы. Gateway работает на WebFlux стеке.

Для service discovery добавьте spring-cloud-starter-netflix-eureka-client или spring-cloud-starter-consul-discovery.

2️⃣ Настраиваем маршруты через application.yml

spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1


lb:// — это magic prefix для балансировки через service discovery. StripPrefix=1 срезает /api перед проксированием запроса вниз.

3️⃣ Пишем кастомный GlobalFilter

@Component
public class AuthFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest()
.getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);

if (token == null || !isValid(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}

@Override
public int getOrder() { return -1; } // выполняется первым
}


getOrder() с отрицательным значением — фильтр выполнится до встроенных. Возвращайте chain.filter(exchange) чтобы пропустить запрос дальше.

4️⃣ Rate Limiting через Redis

filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"

@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}


replenishRate — токенов в секунду, burstCapacity — максимальный burst. Требует spring-boot-starter-data-redis-reactive.

5️⃣ Circuit Breaker с Resilience4j

filters:
- name: CircuitBreaker
args:
name: userServiceCB
fallbackUri: forward:/fallback/users

@RestController
public class FallbackController {
@GetMapping("/fallback/users")
public Mono<String> usersFallback() {
return Mono.just("Users service unavailable");
}
}


Circuit Breaker открывается при превышении порога ошибок и перенаправляет на fallback endpoint вместо каскадного падения.

6️⃣ Настраиваем CORS централизованно

@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");

UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}


Настраивайте CORS на уровне Gateway — не нужно дублировать это в каждом микросервисе.

✔️ Что происходит под капотом

Запрос приходит → RoutePredicateHandlerMapping матчит маршрут по predicates → цепочка GatewayFilter обрабатывает запрос → NettyRoutingFilter проксирует вниз → цепочка фильтров обрабатывает ответ в обратном порядке.

Всё это non-blocking на Project Reactor. Один поток может обрабатывать тысячи одновременных соединений.

💡 Бонус-совет

Actuator endpoint /actuator/gateway/routes покажет все зарегистрированные маршруты в runtime — удобно для дебага. Добавьте management.endpoint.gateway.enabled=true в конфиг и можно динамически обновлять маршруты через /actuator/gateway/refresh без перезапуска.

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

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

#Enterprise

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

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

Scala создан на базе Java, но при этом остаётся более лаконичным и выразительным языком. При этом они отлично сочетаются: вы можете использовать Java-код внутри Scala. На Scala разрабатывают микросервисы, системы аналитики, решения для машинного обучения и обработки данных, а также высоконагруженные сервисы.
Приглашаем на серию открытых уроков перед стартом курса «Scala-разработчик»:

📆1 апреля в 20:00
Разберём функциональную валидацию данных с помощью Cats Validated. Поговорим, почему Either неудобен для таких задач, научимся собирать все ошибки сразу и реализуем валидацию формы регистрации. Вы поймёте, когда использовать Validated, а когда Either, и сможете применять это в реальном коде.

📆14 апреля в 20:00
Изучим ключевые возможности Scala через case classes и pattern matching. На практике разберём, как создавать безопасные модели данных, работать с событиями и писать чистый, понятный код, который используется в production.

📆20 апреля в 20:00
Погрузимся в тему эффектов в Scala. Разберём, что такое эффекты и как они помогают писать предсказуемый и масштабируемый код. Рассмотрим Option, Either, Future, а также Cats Effect и ZIO, и покажем, как применять их в реальных задачах.

💥Присоединяйтесь, чтобы прокачать навыки Scala и функционального программирования на практике. Подробности об уроках и регистрация: https://clc.to/vdc_fw

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

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

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

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

Java Developer — ЮMoney — удалёнка

Java-разработчик — DUC Technologies — удалёнка

Senior Java Developer — Лектон — удалёнка/гибрид (Санкт-Петербург)

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

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

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

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

#DevLife

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

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

Кажется, мы окончательно перешли от игрушек к суровому AgentOps

Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.

На курсе мы:

— пошагово строим готовые системы на LangGraph, CrewAI и MCP;
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.

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

Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.


Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!

Зафиксировать цену и перейти к сборке своих агентов

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

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

🧵 Просто о сложном: ThreadLocal

В многопоточном приложении потоки разделяют общую память. Это создаёт проблемы с состоянием. ThreadLocal решает это элегантно — каждый поток получает свою копию переменной.

🔹 Как устроено внутри

Никакой центральной Map на уровне JVM нет. Всё проще: у каждого объекта Thread есть поле threadLocals типа ThreadLocal.ThreadLocalMap. Это внутренняя Map, которая живёт внутри самого потока.

Когда ты вызываешь set() — значение кладётся в Map текущего потока, где ключ — сам объект ThreadLocal:

// упрощённо, внутри ThreadLocal.set(value)
Thread.currentThread().threadLocals.put(this, value);

get() — достаёт из Map того же потока. Другой поток обращается к своей Map и видит своё значение. Пересечений нет по конструкции.

🔹 Инициализация через withInitial

Если get() вызван, а set() ещё не было, возвращается null. Чтобы этого избежать, используют фабрику:
ThreadLocal<SimpleDateFormat> sdf =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

Лямбда вызовется один раз на поток, при первом get(). Дальше кешируется в той же threadLocals Map.

🔹 Что реально использует ThreadLocal в экосистеме

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

→ TransactionSynchronizationManager — текущее соединение с БД, чтобы сервис и репозиторий в рамках @Transactional работали с одним коннектом
→ SecurityContextHolder — аутентифицированный пользователь
→ RequestContextHolder — текущий HttpServletRequest

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

🔹 Где ломается

Thread Pool. Потоки переиспользуются и после обработки запроса поток возвращается в пул, но его threadLocals Map никуда не девается. Если не вызвать remove(), то следующий запрос, попавший в этот поток, найдёт чужие данные.

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

Второй момент — утечка памяти. ThreadLocalMap использует WeakReference на ключ, но значение держится сильной ссылкой. Если поток живёт долго (а в пуле — фактически вечно) и remove() никто не вызвал — объект не будет собран GC, пока поток жив.

Поэтому паттерн всегда один:
try {
tl.set(value);
// работа
} finally {
tl.remove();
}


ThreadLocal решает конкретную задачу — изоляция состояния без синхронизации. Не серебряная пуля, не замена synchronized. Просто инструмент для случаев, когда данные должны жить в рамках потока, а не шариться между ними.

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

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

#CoreJava

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

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

Скоро на каждом собесе в стране😁

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

#DevLife

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

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

IntelliJ IDEA: The Documentary | An origin story 👩‍💻

Док рассказывает о 25-летнем пути одного из самых любимых инструментов в разработке софта. Благодаря редким архивным кадрам, эксклюзивным интервью и закулисным моментам в нем рассказывается о том, как IntelliJ IDEA бросила вызов существующему положению вещей.

Ты увидишь истории от создателей JetBrains, действующих инженеров и мнения представителей Google, Oracle и сообщества Spring.

🍿 Смотреть
❤️ Полная коллекция доков про различные популярные ЯП, технологии, библиотеки, фреймворки и инструменты

🐸 Библиотека программиста

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

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

✔️ Java-тест: что не так с этим сервисом?

Код компилируется, тесты зелёные, в проде всё ломается 👇

📦 Задание — code review


Сервис обрабатывает заявки на вывод средств. Требования простые: нельзя выводить больше, чем есть на балансе, и нельзя создавать две заявки одновременно.

@Service
@RequiredArgsConstructor
public class WithdrawalService {

private final AccountRepository accountRepository;
private final WithdrawalRepository withdrawalRepository;

public void requestWithdrawal(Long userId, BigDecimal amount) {
Account account = accountRepository.findByUserId(userId)
.orElseThrow();

if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientFundsException();
}

boolean hasPending = withdrawalRepository
.existsByUserIdAndStatus(userId, Status.PENDING);

if (hasPending) {
throw new WithdrawalAlreadyPendingException();
}

account.setBalance(account.getBalance().subtract(amount));
accountRepository.save(account);

withdrawalRepository.save(
new Withdrawal(userId, amount, Status.PENDING)
);
}
}


🔹 Задачи

Два запроса от одного пользователя прилетели одновременно. В итоге — баланс ушёл в минус и создались две заявки.

▪️ Объясни

— Точную последовательность событий при конкурентных запросах.
— Спасёт @Transactional над методом или нет? Почему?
— Как исправить это корректно.

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

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

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

#practise

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

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

Самый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов

Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.

В программе:

— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками LangGraph, AutoGen, MCP и CrewAI;
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.

Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.

Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.


Ах да, чуть не забыли! Дарим промокод AGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁

Освоить разработку AI-агентов

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

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

🖥 На GitHub есть отличный репозиторий

resources-learning-spring — там собраны лучшие материалы для изучения Spring от команды Spring Office Hours. Репозиторий вырос из подкаст-эпизода, где авторы делились любимыми ресурсами, и с тех пор активно пополняется сообществом.

🔹 Внутри найдёте всё по категориям: официальная документация Spring Boot и Spring Framework, книги, YouTube-каналы, подкасты, блоги, конференции и живые GitHub-репозитории с примерами.

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

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

#CoreJava

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

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

🐳 Прокачай Docker CLI

Dockerlings предлагает более 15 упражнений, которые последовательно учат работать с контейнерами, Dockerfile, сетями, томами и многими другими важными аспектами Docker.

Главная особенность — это удобный интерфейс, который позволяющий выполнять задания и сразу же проверять свои решения.

🔗 Пробуй и тренируйся

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

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

#Enterprise

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

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

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

Java-разработчик/Java Developer — гибрид (Москва)

Java (Т-банк) — удалёнка

Senior Java Developer (Cloud-Native) — 4 000$ — удалёнка

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

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

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

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

#DevLife

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

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

☝️ Уже сегодня: ИИ-агенты в продакшене — инженерный подход к интеграции LLM

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

Сегодня в 19:00 МСК в рамках нашего курса «Разработка AI-агентов» мы проведём открытый вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке. Будем говорить о нейросетях с позиции жёсткой инженерии.

Разберём три реальных кейса из сурового банковского энтерпрайза, напишем и запустим агента прямо в эфире, честно обсудим грабли, на которые наступает бизнес при интеграции LLM.

Тем, кто придёт на эфир, дадим промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

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

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

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

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

#DevLife

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