Библиотека джависта | Java, Spring, Maven, Hibernate
23.8K subscribers
2.08K photos
43 videos
43 files
2.93K links
Все самое полезное для Java-разработчика в одном канале.

Список наших каналов: https://t.iss.one/proglibrary/9197

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

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

РКН: https://gosuslugi.ru/snet/67a5bbda1b17b35b6c1a55c4
Download Telegram
💎 Как работает volatile под капотом

Многие знают, что volatile «гарантирует видимость между потоками». Давайте разберёмся, что именно делает это ключевое слово на уровне Java Memory Model (JMM).

1️⃣ Проблема без volatile

В многопроцессорной архитектуре потоки могут обращаться к своим копиям переменных через L1/L2 кэши, а не к основной памяти. Компилятор и процессор активно реорганизуют инструкции (out-of-order, speculative execution), что при отсутствии механизмов синхронизации ведёт к неожиданному поведению в многопоточности.

Если переменная не volatile, один поток может работать со старым значением из кеша и никогда не увидеть обновление другим потоком.

Пример:
class FlagExample {
boolean flag = false;

void thread1() {
while (!flag) {
// бесконечный цикл
}
}

void thread2() {
flag = true;
}
}


JVM и JIT могут оптимизировать while(!flag) так, что значение flag будет читаться один раз и кешироваться локально — и первый поток не выйдет из цикла.

2️⃣ Что делает volatile

🔹 Гарантирует видимость — каждое чтение/запись идёт из основной памяти, а не из локальных кешей

🔹 Гарантирует порядок операций — volatile запрещает компилятору и процессору менять порядок операций до и после чтения/записи

🔹 Гарантирует правило happens-before — запись в переменную будет видна всем потокам, которые читают её после

3️⃣ Что volatile не может

Пример:
volatile int counter = 0;

void inc() {
if (counter < 10) {
counter++; // всё ещё не безопасно
}
}


▪️ Не обеспечивает атомарность

counter++ разваливается на чтение → инкремент → запись. Если два потока сделают это одновременно, одно из увеличений потеряется.
Для атомарных операций используйте атомики или синхронизацию.

▪️ Не заменяет synchronized

volatile гарантирует видимость, но не защищает этот блок от одновременного выполнения разными потоками. Для таких случаев используйте synchronized или Lock.

4️⃣ Где volatile идеально подходит

✔️ Флаги завершения потоков
✔️ Double-checked locking (ленивая инициализация)
✔️ Публикация объекта для многопоточного чтения

Пример double-checked locking:
class Singleton {
private static volatile Singleton instance;

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}


Без volatile JVM могла бы отдать ссылку на не до конца сконструированный объект.

🔗 Документация: Java Memory Model | Volatile

💬 В каких кейсах используете volatile в продакшене?

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

#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥3👏2
💬 А у вас есть тестировщик в команде?

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10👍3🔥1
🆕 JEP 522 — Повышение производительности G1 GC через снижение синхронизации

🔵 Статус и контекст

— JEP 522, авторы — Ivan Walulya и Thomas Schatzl, нацелен на реализацию в JDK 26; последнее обновление датировано 8 сентября 2025 года.
— Согласно дорожной карте JDK 26, окончательное рассмотрение этого JEP запланировано на 15 сентября 2025 года.

🔵 Что меняется

— Предложено снизить накладные расходы на синхронизацию между потоками приложения и сборщика мусора G1, сохранив существующую архитектуру и взаимодействие с пользователем.

— Ключевая идея — внедрение второй таблицы карточек (card table):

▪️ Потоки приложения работают с быстрой, простой, синхронно-нережимой "первой" таблицей
▪️ Потоки-оптимизаторы обрабатывают отдельную вторую таблицу
▪️ При необходимости G1 выполняет атомарный обмен таблицами, позволяя каждому потоку работать автономно и эффективно

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

— Производительность:

▪️ В сценариях с частыми изменениями ссылок в объектах — прирост производительности в диапазоне 5–15 %
▪️ Даже в менее интенсивных сценариях — прирост до 5 % за счёт упрощения write-барьеров (уменьшение с ~50 до ~12 инструкций на x64)

— Снижение пауз GC: более лёгкая структура таблиц карточек и менее громоздкая синхронизация сокращают продолжительность пауз сборщика мусора

— Дополнительная память:

▪️ Вторая таблица занимает ~0,2 % от кучи — порядка 2 МБ на каждый ГБ JVM-кучи
▪️ Несмотря на это, она заменяет более объёмные вспомогательные структуры и не увеличивает общий объём памяти заметно

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

#News
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥41💯1
💬 Во сколько начинается ваш рабочий день?

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
😁9👍2🔥1
🎯 Как настроить аутентификацию с OAuth2

В Spring Boot 3 интеграция с OAuth2 стала ещё проще благодаря улучшенной поддержке социальных логинов. Рассмотрим, как настроить аутентификацию через Google с использованием Spring Security 6.

1️⃣ Создание проекта

Используйте Spring Initializr для создания проекта с следующими зависимостями:

— Spring Web
— Spring Security
— OAuth2 Client

Или добавьте их вручную в pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>


2️⃣ Получение OAuth2-учётных данных Google

1. Перейдите в Google Cloud Console
2. Создайте новый проект
3. Перейдите в раздел APIs & Services → Credentials
4. Нажмите Create Credentials → OAuth 2.0 Client IDs
5. Укажите тип приложения Web application
6. Добавьте Authorized redirect URI
7. Сохраните и получите Client ID и Client Secret

3️⃣ Конфигурация application.yml

Добавьте следующие настройки в src/main/resources/application.yml:
spring:
security:
oauth2:
client:
registration:
google:
client-id: YOUR_CLIENT_ID
client-secret: YOUR_CLIENT_SECRET
scope:
- email
- profile
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
authorization-grant-type: authorization_code
client-name: Google
provider:
google:
authorization-uri: https://accounts.google.com/o/oauth2/v2/auth
token-uri: https://oauth2.googleapis.com/token
user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo
user-name-attribute: sub


Замените YOUR_CLIENT_ID и YOUR_CLIENT_SECRET на полученные значения.

4️⃣ Конфигурация безопасности

Создайте класс конфигурации:
@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login", "/error").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.defaultSuccessUrl("/dashboard", true);
return http.build();
}
}

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

#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥2🎉1
💬 У кого сегодня деплой?

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8🔥1🥰1👏1😍1
⚙️ Интеграция системы логирования с Logback в Spring Boot

Ищете, как настроить логирование в приложении на Spring Boot? Используйте Logback для эффективного логирования и управления уровнями логов. Используйте AI для ускорения процесса.

📝 Промпт:


Generate a logging system integration for a Spring Boot 3 application using Logback.

— Set up logback-spring.xml for flexible configuration of logging levels and appenders.
— Define rolling file appender to archive old log files based on size or date.
— Configure log format with PatternLayoutEncoder for structured and readable logs.
— Implement different logging levels (INFO, WARN, ERROR) for different components of the application.
— Integrate MDC (Mapped Diagnostic Context) for tracking user sessions or specific requests.
— Set up asynchronous logging with AsyncAppender to improve performance in high-traffic applications.
— Enable console logging for development and file logging for production environments.


💡 Расширения:

— Добавьте Set up rolling file appender for log rotation based on size or date для архивирования старых логов.
— Добавьте Implement asynchronous logging with AsyncAppender для улучшения производительности в высоконагруженных приложениях.
— Добавьте Integrate custom appenders for external monitoring systems like Elasticsearch or Splunk для интеграции с внешними системами мониторинга.

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

#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72🔥1
🎧 Что послушать — #подкаст

🔹 Javaswag #80
Дата выпуска: 22 августа 2025
Ведущий: Дмитрий Волыхин
Гость: Илья Зонов, архитектор
Продолжительность: примерно 2 часа 6 минут

В выпуске обсуждают роль архитектора, подход API First, книгу Code of Architecture, жизненный баланс на высоких ставках, работу с Kafka и сериализацией, а также многие другие аспекты разработки и архитектуры в мире IT.

🔹 Ключевые темы выпуска

00:00 — Начало
06:03 — Linux и эмбеддед системы
12:57 — Проекты на Java
19:03 — Постгресс и банки
30:31 — PostgreSQL
34:55 — Бизнес-процессы
42:13 — Процесс разработки в малых и крупных компаниях
49:12 — Принятие решений в команде
55:16 — Work-life balance на высоких ставках
01:00:36 — Подход API First
01:14:23 — Роль архитектора и Kotlin
01:17:23 — Генерация клиентов
01:25:10 — Книжный клуб Code of Architecture
01:33:48 — Мотивация
01:40:45 — Чтение книг
01:47:29 — Инструменты для работы с текстом и заметками
01:55:10 — Vim и Emacs
01:56:52 — Ответ на предыдущее непопулярное мнение
02:01:35 — Готовность к изменениям

🔗 Слушать выпуск

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥21
💬 На какой ОС работаете?

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17💯3👍1
🔍 Просто о сложном: что такое Garbage Collector (GC)?

Garbage Collector (GC) в Java — это механизм автоматического управления памятью, который отвечает за очистку памяти от объектов, которые больше не используются в программе. Вместо того, чтобы разработчик вручную освобождал память, как в некоторых других языках программирования, Java использует сборщик мусора, который делает это автоматически.

🔵 Как работает GC?

Когда вы создаёте объект в Java, он занимает место в куче (heap) — области памяти, предназначенной для динамического распределения. Однако по мере работы программы некоторые объекты становятся ненужными, и их можно удалить, чтобы освободить память для других задач. Это и есть основная задача GC — найти объекты, которые больше не используются, и освободить память.

🔵 Основные этапы работы GC

1. Маркировка. На первом этапе система анализирует объекты в куче и помечает те, на которые существуют ссылки, то есть которые всё ещё могут быть использованы в программе. Эти объекты называют живыми.

2. Сборка мусора. После маркировки GC удаляет объекты, которые не были помечены как «живые». Эти объекты больше не используются в программе и могут быть безопасно удалены, а занимаемое ими пространство освобождается.

3. Компактизация (Compaction). Иногда после удаления объектов в куче остаются фрагменты пустой памяти. В этом случае GC может перемещать объекты, чтобы устранить фрагментацию и сделать память более сплошной. Это улучшает использование доступных ресурсов.

🔵 Типы Garbage Collector в Java

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

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

Parallel GC: этот сборщик использует несколько потоков для работы, что ускоряет процесс очистки. Он подходит для многозадачных приложений и приложений с большими объемами данных, где важно минимизировать время пауз.

CMS (Concurrent Mark-Sweep): сборщик мусора, который работает параллельно с основной программой, минимизируя паузы. Он использует несколько шагов для маркировки и уборки мусора, чтобы не блокировать выполнение приложения на долгое время.

G1 (Garbage First): один из самых современных сборщиков мусора. Он фокусируется на минимизации времени пауз и дает разработчикам больше контроля над процессом. G1 отлично подходит для больших приложений с высоким уровнем взаимодействия.

🔵 Паузы и их влияние на производительность

Одним из главных аспектов работы GC является Stop-the-World пауза, когда приложение временно приостанавливается, чтобы сборщик мусора очистил память. Хотя паузы в большинстве случаев довольно короткие, они могут заметно повлиять на производительность, особенно в приложениях с высокими требованиями к времени отклика.

🔵 Как улучшить производительность при работе с GC

Оптимизация размера кучи. Размер кучи можно настроить в зависимости от объема данных, с которым работает ваше приложение. Неправильно выбранный размер может привести к слишком частым или слишком редким сборкам мусора.

Использование правильного сборщика. Выбор сборщика мусора зависит от особенностей вашего приложения. Например, для приложений с требованием низкой задержки лучше использовать G1 или CMS.

Профилирование. Используйте инструменты профилирования, чтобы отслеживать, как работает GC в вашем приложении. Это поможет выявить проблемы и оптимизировать использование памяти.

🔵 Когда стоит задуматься о Garbage Collector

— Когда ваше приложение работает с большим количеством объектов, и необходимо следить за производительностью.
— Если заметны задержки или паузы, вызванные работой GC, и нужно оптимизировать работу с памятью.
— В сложных многозадачных или распределённых приложениях, где важно, чтобы GC не блокировал выполнение других задач.

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

#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101🔥1👏1
🔥 Последняя неделя перед стартом курса по AI-агентам

Старт курса уже 15го числа! Если вы планировали вписаться — сейчас ПОСЛЕДНИЙ шанс забронировать место

На курсе:
разложим LLM по косточкам: токенизация, SFT, PEFT, инференс
— соберём RAG и научимся оценивать его адекватно
— построим настоящую мультиагентную систему — архитектуру, которая умеет расти
— разберём CoPilot, сломаем через prompt injection (спасибо Максу)
— и наконец, посмотрим, как это работает в MCP и реальных кейсах

📍 Это 5 живых вебинаров + раздатка + домашки + чат с преподавателями

И главное — возможность реально разобраться, как проектировать системы на LLM, а не просто «поиграться с API»

Промокод на 5.000₽: LASTCALL

👉 Курс здесь
1
🆕 Java Digest: Java 25, кэширование и оптимизация Maven

Топ-3 статьи о Java за неделю по мнению нашего канала. Нововведения Java 25, паттерны кэширования для микросервисов и оптимизации сборки с помощью Maven.

1️⃣ PVS-Studio: Нововведения Java 25

PVS-Studio в своей статье подробно рассматривает нововведения в Java 25, включая новые API, улучшения синтаксиса и поддержку функционального программирования.

Cтоит отметить появление ScopedValue, который решает проблемы с ThreadLocal, а также возможность использования компактных исходных файлов и методов main.

2️⃣ OTUS: Пять производительных паттернов кэширования

В статье от OTUS рассматриваются пять основных паттернов кэширования, которые могут значительно повысить производительность микросервисов. Каждый паттерн, от Cache-Aside до Write-Back Cache, имеет свои особенности и сценарии применения.

3️⃣ Spring АйО: Maven — verify или clean install

Особенно рекомендую статью от Spring АйО. Всегда использовал mvn clean install, и, думаю, так делают многие из вас.

Статья посвящена вопросам оптимизации сборки проектов с использованием Maven. Также обсуждается, когда можно обойтись без clean install.

💬 Пишите, понравилась ли подборка?

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

#News
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🎉2🔥1
👀 Задача с собеса: Поиск наибольшей общей подпоследовательности (LCS) (mid+)

Найдите длину наибольшей общей подпоследовательности (LCS) двух строк:

— Даны две строки A и B.
— Нужно найти длину наибольшей общей подпоследовательности между ними.


▪️ Условия

1. Строки могут быть длиной до 1000 символов.
2. Используйте динамическое программирование для решения.
3. Подсчитайте длину LCS.

💡 Ключевые моменты

— Используйте таблицу для хранения промежуточных результатов.
— Если символы в строках совпадают, то прибавляйте 1 к предыдущему значению. Если не совпадают — выбирайте максимум из предыдущих значений.
— Убедитесь, что алгоритм работает с большими строками за время O(n*m), где n и m — длины строк.

💬 Возможная реализация в комментариях. Пишите свои варианты и обсудим разные подходы.

🐸 Библиотека собеса по Java
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2🔥1
☕️ Java && Coffee

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

Как проходят ваши выходные? Отправляйте фото в комментарии👇🏻

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

#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
😍10👍5🔥31🥰1
👑 Магия IntelliJ IDEA: Multi-Caret Editing

Хотите править код сразу в нескольких местах? Multi-Caret Editing позволяет поставить несколько курсоров и синхронно редактировать текст.

🔹 Что делает

— Позволяет редактировать одинаковые участки кода одновременно
— Ускоряет массовое переименование переменных, правки форматирования и шаблонных конструкций
— Работает не только в коде, но и в файлах конфигурации, JSON, XML

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

— Экономит время при рутинных правках
— Снижает вероятность пропустить один из повторяющихся фрагментов
— Делает код-ревью и рефакторинг быстрее

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

— Выделите слово и нажмите Alt+J (Windows/Linux) или Ctrl+G (macOS) — добавится второй курсор
— Продолжайте нажимать, чтобы выбрать следующие вхождения
— Для выбора сразу всех вхождений используйте Ctrl+Alt+Shift+J
— Для произвольных позиций используйте Alt+Click для добавления курсора в нужное место

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

#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92🔥2🤔2
📈 Big-O ≠ производительность

Часто выбор коллекции ограничивается только таблицей сложностей и на этом всё.

Но реальный кейс сложнее: средняя сложность ≠ реальная скорость в продакшне. JVM, кэш процессора, GC и паттерны доступа могут радикально поменять картину.

🔑 Главная мысль

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

1️⃣ ArrayList — быстр в чтение, но не во вставке

ArrayList хранит элементы в массиве → локальность памяти + CPU кэш → итерации летят.
Вставка в середину за O(n), но при небольших списках разница с LinkedList исчезающе мала.

🔧 Паттерн использования:

— 90% чтение, редкие вставки → идеально.
— Если заранее известно примерное кол-во элементов → задайте initialCapacity, иначе ArrayList будет несколько раз пересоздавать массив (copy O(n) на каждом росте).

📌 Факт:

В бенчмарках JMH даже при вставке в середину ArrayList часто быстрее LinkedList просто потому, что LinkedList платит за “pointer chasing” (скачки по памяти, cache-miss).

2️⃣ LinkedList — звучит круто, но редко нужен

Да, вставка/удаление в начало или конец за O(1).
Но get(i) = O(n), и каждый шаг = новый объект, новая ссылка → нагрузка на GC.

🔧 Паттерн использования:

— Когда нужна двусторонняя очередь с частыми удалениями/добавлениями в начало и конец.
— Во всех остальных случаях лучше ArrayDeque, он без лишних объектов и быстрее почти всегда.

📌 Факт:

LinkedList ест больше памяти: на каждый элемент два указателя + объект-узел.

3️⃣ HashMap / HashSet — быстрые, пока не наступил resize

HashMap даёт O(1) доступ при хорошем hashCode().

Но:
— Если хэши “плохие” → коллизии → O(log n)
— При достижении load factor 0.75 → resize → перераспределение всех бакетов (дорогая операция).

🔧 Паттерн использования:

— Когда нужен быстрый поиск по ключу без сохранения порядка или когда важно хранить уникальные элементы или строить словари/кэши по ключу.
— Если знаете примерное кол-во элементов → сразу задайте кол-во элементов в конструкторе new HashMap<>(N).

📌 Факт:

Начиная с Java 8 при коллизии, когда LinkedList становится длинным (по умолчанию ≥ 8 элементов) → список превращается в красно-чёрное дерево.

4️⃣ TreeMap / TreeSet — порядок стоит денег

Дают O(log n) доступ и всегда хранят ключи отсортированными.
Но если сортировка нужна редко, дешевле собрать HashMap и вызвать sorted() на стриме.

🔧 Паттерн использования:

— Когда важно поддерживать сортировку на каждой операции (напр. Top-N задач в приоритетной очереди).
— Не храните mutable-ключи, т.к. можно “потерять” элемент при изменении поля, участвующего в compareTo.

📌 Факт:

TreeMap хранит узлы с балансировкой (красно-чёрное дерево) → накладные расходы на память + сравнения ключей.

5️⃣ LinkedHashMap — скрытый герой для кэшей

LinkedHashMap поддерживает порядок вставки или порядок доступа (accessOrder=true).
Можно сделать LRU-кэш, переопределив removeEldestEntry.

🔧 Паттерн использования:

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

📌 Факт:

Каждый get() в режиме accessOrder вызывает перестановку в двусвязном списке → небольшие накладные расходы.

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

#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍217🔥3
🎯 Интеграционные тесты с Testcontainers

Пошаговая настройка тестов на Spring Boot 3 с Testcontainers + PostgreSQL: быстро, изолированно, воспроизводимо.

1️⃣ Зависимости (Maven/Gradle)

— Maven (pom.xml):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.20.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>


— Gradle (Kotlin DSL):
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
testImplementation("org.flywaydb:flyway-core")
testImplementation("org.postgresql:postgresql")
testImplementation(platform("org.testcontainers:testcontainers-bom:1.20.3"))
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")
}


2️⃣ Включаем Testcontainers

C Spring Boot 3.1 контейнер можно подключить одной аннотацией без ручного прописывания spring.datasource.*.
@Testcontainers
@ExtendWith(SpringExtension.class)
@SpringBootTest
class PostgresIT {

@Container
@ServiceConnection // Spring сам подставит URL/логин/пароль в DataSource
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("app")
.withUsername("app")
.withPassword("secret");

@Test
void contextLoads() {
// проверяем, что контекст и datasource поднялись на контейнере
}
}


3️⃣ Миграции для тестов (Flyway)

Положите миграции в src/test/resources/db/migration (отдельно от продовых — удобно для фикстур):
src/
└─ test/
└─ resources/
└─ db/
└─ migration/
├─ V1__init.sql
└─ V2__seed.sql


4️⃣ Ускоряем прогоны

▪️ Reusable containers (кэшируемый демон): добавьте в ~/.testcontainers.properties
testcontainers.reuse.enable=true

и .withReuse(true) для контейнера в тесте.

▪️ Singleton-паттерн контейнера: вынесите контейнер в общий абстрактный класс теста, чтобы один контейнер работал на все тесты.

5️⃣ Полезные трюки и подводные камни

— Если на MacOS/Colima, проверьте доступность Docker API (docker info) перед тестами.
— Для детерминизма фиксируйте теги образов (например, postgres:16-alpine), не latest.
— Логи контейнеров доступны: postgres.followOutput(...) — удобно для диагностики нестабильных тестов.
— Если нужен R2DBC: поднимайте Postgres как выше, а в application-test.yml указывайте r2dbc URL; @ServiceConnection корректно сконфигурирует оба коннектора, если они в classpath.
— Тяжёлые фикстуры → создавайте через SQL-маски (V*_seed.sql) или @Sql прямо в тестах — не смешивайте тестовые данные с продовыми миграциями.

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

#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍32