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

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

@javaproglib

Все самое полезное для Java-разработчика в одном канале.

Учиться у нас: clc.to/AATM8w

Для обратной связи: @proglibrary_feeedback_bot

По рекламе: @tproger_sales_bot

РКН: https://gosuslugi.ru/snet/67a5bbda1b17b35b6c1a55c4
Subscribers
22K
Photos
2.5K
Videos
57
Links
3.7K

Showing posts older than #7558 · Back to latest

Older Posts 20 shown
Post #7557 2.31K
🔧 Spring Security 6: конфигурация без устаревших паттернов

WebSecurityConfigurerAdapter удалён в Spring Security 6. Новый подход — компонентная модель через SecurityFilterChain. Разбираем актуальную конфигурацию.

🔹 Решение

▪️ Базовая конфигурация

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // включает @PreAuthorize, @PostAuthorize
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers("/api/webhooks/**"))
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter())))
.exceptionHandling(ex -> ex
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler()))
.build();
}

@Bean
public JwtAuthenticationConverter jwtConverter() {
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthoritiesClaimName("roles");
converter.setAuthorityPrefix("ROLE_");

JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
return jwtConverter;
}
}


▪️ Несколько SecurityFilterChain для разных путей


@Bean
@Order(1)
public SecurityFilterChain actuatorChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/actuator/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.anyRequest().hasIpAddress("10.0.0.0/8"))
.build();
}

@Bean
@Order(2)
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.build();
}


▪️ Method-level security

@Service
public class OrderService {

@PreAuthorize("hasRole('ADMIN') or #userId == authentication.name")
public List<Order> getOrders(String userId) { ... }

@PostAuthorize("returnObject.userId == authentication.name")
public Order getOrder(Long orderId) { ... }
}


Несколько SecurityFilterChain с @Order — правильный способ применять разные политики безопасности к разным частям приложения. securityMatcher определяет к каким путям применяется цепочка. Первая совпавшая цепочка побеждает.

⚠️ hasIpAddress для actuator в production — минимум. Идеально вынести actuator на отдельный порт (management.server.port=8081) и закрыть его на уровне сети.

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

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

#Enterprise
  • 👍 8
  • ❤ 3
  • 🔥 2
Post #7556 2.43K
⚡️ Просто о сложном: почему Redis такой быстрый

Стандартный ответ — «потому что in-memory». Это правда, но не объяснение. Куча баз данных хранит данные в памяти и не показывает таких цифр. Настоящий ответ в другом: каждое архитектурное решение Redis убирает конкретный источник latency.

🧵 Один поток

Redis обрабатывает команды последовательно в один поток. Никаких мьютексов, никакого context switching. Тысячи соединений при этом обслуживаются через epoll/kqueue — один поток следит за всеми сокетами через I/O multiplexing и не блокируется ни на одном из них.

📦 Адаптивные структуры

Hash с небольшим числом ключей хранится не как хэш-таблица, а как listpack — плотный байтовый массив, который влезает в один cache line. Никаких pointer chasing. Только когда данных становится много, Redis переключается на полноценную хэш-таблицу. Sorted Set — одновременно хэш-таблица и skiplist. O(1) по ключу и O(log N) для range-запросов без второго прохода.

💾 fork()

Снапшот RDB пишется дочерним процессом после fork(). Благодаря CoW основной процесс продолжает работу и не видит никакой паузы — ОС копирует только изменённые страницы памяти. AOF идёт дальше и логирует каждую команду, давая возможность восстановиться до последней записи. Точнее, но дороже — компромисс осознанный.

🧹 bounded expiry

Ключи с истёкшим TTL удаляются двумя способами: лениво при обращении и активно — каждые 100 мс Redis сэмплирует случайную выборку и чистит просроченные. Если таких больше 25%, повторяет цикл. Это не O(N) по всей базе, а предсказуемая нагрузка с жёстким потолком по CPU.

Redis — это не «база данных в памяти». Это система, где каждый выбор — однопоток, listpack, fork(), bounded expiry — существует потому, что альтернатива добавляла latency. In-memory здесь просто необходимое условие, а не причина скорости.

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

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

#CoreJava
  • ❤ 8
  • 👍 6
  • 🔥 2
Post #7555 2.24K
🤫 Один раз можно и на фронт

Пишешь или только готовишься писать бэк, проектируешь API, знаешь про pool'ы и понимаешь, чем @Transactional на private-методе отличается от пустой строки. Круто! А как обстоят дела с пониманием, что по ту сторону HTTP запроса?

Если думаешь про full stack или просто интересно разобраться, что происходит на фронте — подписывайся на канал коллег. Они про frontend: без воды, для тех, кто умеет думать технически.

👉 Библиотека фронтендера

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

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

#DevLife
  • 👍 2
  • 🔥 1
  • 😁 1
Post #7554 2.57K
🔧 resilience4j — 10.6k ⭐️

Писал обёртку вокруг HTTP-клиента с ручным retry, таймаутами и какой-то самописной логикой «если упало три раза — не зови больше»? resilience4j это то, что ты изобретал заново.

Библиотека даёт готовые примитивы отказоустойчивости: Circuit Breaker, Rate Limiter, Retry, Bulkhead, TimeLimiter. Всё через декораторы поверх функциональных интерфейсов — накидываешь нужное, не трогая бизнес-логику.

Supplier<String> decorated = Decorators.ofSupplier(backendService::call)
.withCircuitBreaker(circuitBreaker)
.withRetry(retry)
.withRateLimiter(rateLimiter)
.decorate();


Resilience4j 3 требует Java 21, из коробки интегрируется со Spring Boot 4, есть метрики для Prometheus/Grafana.

📱 Репозиторий

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

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

#Enterprise
  • 👍 4
  • 🔥 2
  • ❤ 1
Post #7553 2.48K
🖥 Ты когда-нибудь превращал микросервис в монолит с распределёнными страданиями?

40 Transaction Script методов, всё выглядит чисто. Потом появляется реальная бизнес-логика — и updateEmployee разрастается до 1000 строк с флагами и if-else на каждый чих.

Выход — агрегаты из DDD. Не как религия, а как прагматичный инструмент.

3 правила, которые реально работают:

→ одна транзакция = один агрегат
→ ссылки между сервисами только через ID, никаких объектных связей
→ агрегат маленький, но достаточный для защиты инвариантов

Плюс разбор того, как уволить 5000 сотрудников без того, чтобы положить базу на 30 секунд.

🔗 Cтатья с живыми примерами

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

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

#Enterprise
  • ❤ 6
  • 👍 1
  • 🔥 1
Post #7552 2.42K
👁 Паттерн Observer

Observer — поведенческий паттерн, который создаёт механизм подписки: одни объекты следят за событиями других и реагируют на них. Источник событий не знает, кто именно подписан и что произойдёт.

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

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

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

1️⃣ Слабая связанность

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

2️⃣ Динамическая подписка

Подписчики добавляются и удаляются в рантайме. Поведение системы меняется без перекомпиляции.

3️⃣ Соответствие принципу Open/Closed.

Новая реакция на событие — новый подписчик. Источник и существующие подписчики не меняются.

⚠️ Утечки памяти. Подписчик, который не отписался — не будет собран GC, пока жив источник.

В Spring: ApplicationEventPublisher + @EventListener — это Observer из коробки. Добавить @Async к слушателю и подписчик изолирован от основного потока.

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

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

#CoreJava
  • 👍 6
  • ❤ 2
  • 🔥 1
Post #7548 2.42K
🧵 Просто о сложном: Kubernetes

Не DevOps-гайд, не «как установить кластер». Именно то, с чем ты столкнёшься как разработчик когда твой сервис едет в K8s.

🔹 Что куда деплоится


Твой jar живёт в Docker-образе. Образ запускается как Pod — минимальная единица в K8s. Pod эфемерен: упал, рестартовал, переехал на другую ноду — это нормально, это не баг.

Нода — это физическая или виртуальная машина в кластере.

Кластер состоит из нескольких нод, на каждой из них K8s запускает поды. Когда нода падает или уходит на обслуживание — K8s автоматически перезапускает её поды на других нодах.

Как разработчику тебе не нужно знать на какой ноде живёт твой под, K8s сам решает это на основе requests ресурсов.

Чтобы управлять несколькими копиями пода используют Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
spec:
containers:
- name: order-service
image: order-service:1.4.2
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"


requests — сколько K8s резервирует для пода при планировании. limits — жёсткий потолок. Превысил memory limit — OOMKill. Превысил CPU limit — троттлинг.

Это напрямую влияет на JVM: именно от limits.memory нужно считать -XX:MaxRAMPercentage.

🔹 Как сервисы находят друг друга

Pod умирает и поднимается с новым IP. Поэтому обращаться к поду напрямую нельзя. Service — стабильный DNS-адрес и балансировщик поверх набора подов.

apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 8080


Внутри кластера твой payment-service обращается к order-service просто по имени

K8s DNS резолвит это в нужный ClusterIP. Никаких Eureka, никакого Consul — для базового service discovery это не нужно.

🔹 K8s не знает что твой сервис готов


K8s видит что контейнер запустился. Но не знает что Spring контекст поднялся, Liquibase отработал и сервис готов принимать трафик.

livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10

readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5


Readiness — сервис готов принимать трафик. Пока не прошёл, pod исключается из балансировки Service.

Liveness — сервис живой. Не прошёл несколько раз подряд, pod рестартует. Сюда не стоит вешать проверку зависимостей (БД, кафка) — если БД легла, рестарт сервиса не поможет.

Spring Boot Actuator отдаёт оба эндпоинта из коробки при management.endpoint.health.probes.enabled=true.

🔹 ConfigMap и Secret

Хардкодить урлы и пароли в application.properties внутри образа — плохая идея. Образ должен быть одинаковым для dev, staging и prod.

apiVersion: v1
kind: ConfigMap
metadata:
name: order-service-config
data:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/orders
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092

---

apiVersion: v1
kind: Secret
metadata:
name: order-service-secret
data:
SPRING_DATASOURCE_PASSWORD: cGFzc3dvcmQ= # base64


В Deployment пробрасываешь как env-переменные — Spring Boot подхватывает автоматически через @Value или application.properties биндинг.

Kubernetes не требует от разработчика знания всего кластерного стека. Но понимать как твой сервис деплоится, как K8s решает готов ли он к трафику и как корректно завершает работу — это уже твоя зона ответственности, не DevOps.

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

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

#CoreJava
  • 👍 6
  • ❤ 2
  • 🔥 1
Post #7546 2.57K
🐳 Магия Docker CLI

Контейнер запустился, но ведёт себя странно — не то сетевое окружение, не те переменные, непонятно что вообще внутри? Просто запустите docker inspect, и у вас будет полная картина без лишних инструментов.

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

— Возвращает полный JSON с внутренностями: переменные окружения, тома, сетевые настройки, лимиты ресурсов, entrypoint, restart policy.
— Работает не только с контейнерами — понимает образы, тома и сети.
— Незаменимо, когда нужно быстро понять, почему контейнер ведёт себя не так, как ожидается.

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

— Полный дамп: docker inspect my-container
— Только IP-адрес: docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-container
— Все переменные окружения: docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' my-container
— Смонтированные тома: docker inspect -f '{{json .Mounts}}' my-container | jq

Флаг -f принимает Go-шаблоны — вытащите ровно то поле, которое нужно, без парсинга тысячи строк JSON вручную.

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

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

#Enterprise
  • ❤ 4
  • 👍 4
  • 🔥 1
Post #7544 2.68K

Forwarded from Библиотека собеса по Java | вопросы с собеседований

✔️ 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();
}
}


▪️ Объясни

— Точную механику N+1: где и сколько раз запросы уходят в БД в этом коде.
— Почему FetchType.EAGER «решит» проблему, но создаст другую.
— Как можно решить проблему.

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

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

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

#practise
  • 🔥 22
  • ❤ 5
Post #7543 2.92K
📨 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.


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

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

#Enterprise
  • 🥱 10
  • ❤ 3
  • 👍 1
  • 👾 1
Post #7541 2.74K
✌🏻 У нас две новости — хорошая и плохая!

Хорошая: Ваших знаний, скорее всего, хватит, чтобы собрать рабочую демку AI-агента в Colab. 🫡

Плохая: Вы вряд ли выведете его в прод, не обанкротившись на токенах и не слив базу. 🤯

Для защиты от таких сценариев мы полностью пересобрали курс «Разработка AI-агентов». Теперь внутри плотная работа с экономикой ресурсов, дебаг через time-travel в LangGraph, извлечение данных из кривых сканов для RAG и комплаенс по 152-ФЗ.

Если всё ещё сомневаетесь, послушайте голосовое от спикера курса Влада Прошинского, где он объясняет, как правильно тестировать агентов перед релизом.


Программа курса, полный состав спикеров и другие подробности 👈🏻

ВАЖНО! До 5 апреля на курс действует скидка, но свободные места могут закончиться раньше.
  • 🥱 4
Post #7539 2.87K
🎁 Паттерн Decorator

Decorator — структурный паттерн, который добавляет объектам новое поведение, оборачивая их в объекты-обёртки. Альтернатива наследованию, когда комбинаций поведения много и они меняются в рантайме.

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

🔹 Когда нужно добавить поведение объекту, не меняя его класс и не трогая остальные объекты.
🔹 Когда наследование порождает взрывной рост классов из-за комбинаций поведений.
🔹 Когда поведение нужно добавлять и убирать динамически в рантайме.

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

1️⃣ Гибкость комбинирования поведений

Каждый декоратор делает одно дело. Нужно кеширование + логирование + метрики? Оборачиваете в три слоя в любом порядке. Не нужны метрики — просто не добавляете этот слой.

2️⃣ Единая ответственность

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

3️⃣ Прозрачность для клиента

Декоратор реализует тот же интерфейс, что и оригинал. Клиентский код не знает, с чем работает — с оригиналом или с обёрткой.

⚠️ Порядок декораторов имеет значение. Метрики снаружи кеша видят кеш-хиты корректно. Метрики внутри — не видят их вообще.

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

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

#CoreJava
  • 👍 5
  • ❤ 1
Post #7537 2.61K
🖥 JDK 21 или 25, что выбрать новичку

Вышла Java 25, которую все хотят попробовать. Но ставить ли её или взять проверенную Java 21 LTS?

В этом гайде — пошаговая установка Java на Windows с картинками, разбор различий между версиями, настройка JAVA_HOME и PATH.

Ориентирован для начинающих разработчиков, изучающих Java

🔗 Читайте в статье

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

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

#Enterprise
  • ❤ 1
  • 👍 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →