Telegram Web
В статье разбираем, почему graceful shutdown важен и как настроить плавное завершение работы Spring Boot приложения, которое работает с Kafka.

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

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3
Гибкие тела конструкторов в Java 25

→ Одна из самых заметных фич, введённых в Java 25.
→ Основная идея: ослабить строгие правила, согласно которым super(...) или this(...) обязательны как первая инструкция в конструкторе.

→ А что, если нужно что-то сделать с аргументами перед передачей их суперклассу?
Допустим, мы хотим проверить число перед вызовом super(). Раньше это было невозможно, так как Java строго требовала, чтобы первой строкой любого конструктора был вызов другого конструктора в том же классе (this(...)) или конструктора суперкласса (super(...)).

В приведённом примере:

→ До Java 25, если конструктору PositiveNumber нужно было передать val в его суперкласс BaseNumber (который требует val в конструкторе), super(val) должен был быть первой строкой. Любой код перед super() приводил к ошибке: "super() должен быть первой инструкцией".

→ Отложенная проверка: В примере мы не могли проверить val до его использования для инициализации BaseNumber, что нарушало принцип "fail-fast". Если val = -1, BaseNumber всё равно инициализировался с -1, прежде чем PositiveNumber мог бы выбросить ошибку.

→ Неуклюжие обходные пути: Чтобы проверить аргумент заранее, приходилось использовать менее читаемые схемы (например, super(staticMethodForValidation(val))) или сложную делегацию конструкторов.

⇒ С Java 25

→ Теперь Java 25 понимает, что подготовительная работа, такая как проверка аргументов, логически относится к обязанностям конструктора и может (и должна) выполняться до инициализации состояния суперкласса.

→ Настоящая проверка "fail-fast": Если val = -1, IllegalArgumentException выбрасывается до вызова super(val), конструктор BaseNumber не выполняется с некорректным значением, и создание объекта прерывается на раннем этапе.

→ Более безопасное создание объектов: Суперкласс инициализируется только с корректными, предварительно обработанными аргументами, что делает объекты более надёжными и безопасными.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82
This media is not supported in your browser
VIEW IN TELEGRAM
Терминальный интерфейс для Docker на Rust

Приложение позволяет просматривать и управлять контейнерами, образами, томами и сетями прямо из терминала, вдохновлено K9s и делает работу с Docker быстрее и удобнее.

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

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5
Вопросы по Java + Spring Boot на собеседованиях (сценарии из реальной практики)

Ниже приведены несколько типичных сценариев с короткими ответами (TL;DR — можно сохранить для повторения перед интервью):

🔸Типы Spring-бинов и стереотипы

Сценарий: Представь, что ты проектируешь сложную e-commerce платформу. Где ты используешь интерфейс с аннотацией
@Repository, а где — с аннотацией @Service? Приведи конкретный пример, какую роль каждая из этих аннотаций играет в процессе оформления заказа пользователем.


@Component — универсальный бин,
@Service — бизнес-логика,
@Repository — DAO + перевод исключений в DataAccessException,
@Controller — контроллер уровня MVC.

🔸Циклические зависимости

Сценарий: Коллега добавил новую фичу, и теперь твое Spring-приложение не стартует, выдавая BeanCurrentlyInCreationException из-за циклической зависимости между ServiceA и ServiceB.
Предположим, что быстро переработать бизнес-логику невозможно. Какое минимальное изменение кода ты бы предложил, чтобы приложение хотя бы запустилось, и почему это считается временным решением?


Spring по умолчанию может использовать проксирование и конструкторную/сеттерную инъекцию.
Лучшее решение — перепроектировать зависимости или использовать @Lazy.

🔸Распространение транзакций

Сценарий: У тебя есть OrderService с методом createOrder(), помеченным @Transactional.
Внутри он вызывает updateInventory() (тоже в OrderService и тоже с @Transactional).
Если updateInventory() выбрасывает runtime-исключение, что произойдет с транзакцией, начатой в createOrder()?
Как изменить дизайн, если нужно, чтобы оба метода выполнялись в отдельных, независимых транзакциях?


Транзакция не будет распространяться (прокси не сработает при внутреннем вызове).
Решение — self-injection (внедрение самого себя как зависимости) или использование AOP.

🔸Скоупы бинов

Сценарий: Нужно хранить товары пользователя в корзине и управлять временным списком поисковых фильтров, который очищается после каждого HTTP-запроса.
Какой скоуп ты выберешь для ShoppingCart и какой — для SearchFilter, и почему?


@SessionScope — для корзины (привязано к пользовательской сессии),
@RequestScope — для поискового фильтра (новый бин на каждый HTTP-запрос).

🔸Controller Advice

Сценарий: В приложении есть и традиционные веб-эндпоинты с Thymeleaf, и REST API.
Нужно централизовать обработку ошибок (например, перехват ResourceNotFoundException):

Как вернуть страницу 404 для обычных web-эндпоинтов?

Как вернуть JSON с ошибкой 404 для REST API?


@ControllerAdvice — используется с @Controller, возвращает view.
@RestControllerAdvice — сочетает @ControllerAdvice + @ResponseBody (для REST API).

🔸Автоконфигурация

Сценарий: Ты добавил в проект стороннюю библиотеку (например, кастомный логгер) и просто положил её JAR в classpath.
Без написания конфигурационных классов Spring автоматически подхватывает нужные бины.
Объясни, как Spring Boot определяет и подключает их при старте.


Использует SpringFactoriesLoader, который читает META-INF/spring.factories и конфигурирует бины в зависимости от содержимого classpath.

🔸Ограничение частоты запросов

Сценарий: Твой публичный API перегружен — один клиент шлет слишком много запросов, мешая остальным.
Какой практичный, независимый от технологий подход можно применить для ограничения, например, 100 запросов в минуту на клиента, и где обычно реализуется такая логика?


Bucket4j / Resilience4j, счетчики в Redis, лимитирование на уровне API Gateway.

🔸Распределённые транзакции

Сценарий: В микросервисной архитектуре оформление заказа включает два шага — списание товара в Inventory Service и списание денег через Payment Service.
Если списание товара прошло успешно, а оплата — нет, какой шаблон проектирования поможет откатить изменения в Inventory и обеспечить согласованность данных?


Шаблон Saga (хореография или оркестрация), либо двухфазный коммит (2PC, но редко используется на практике).

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍5
Как правильно обрабатывать ошибки в Spring Boot REST

Если ты делаешь REST-API на Spring Boot, важно не просто ловить исключения, а возвращать понятные ответы клиенту. Корректные HTTP-коды и осмысленные сообщения помогают быстрее понять, что пошло не так — будь то дубликаты записей, ошибки валидации или проблемы с аутентификацией.

В статье объясняется, как организовать централизованную обработку ошибок, какие статусы стоит использовать (400, 401, 404, 409, 500 и т.д.), и почему логирование играет ключевую роль в поддержке и быстром устранении проблем в проде.

Подробнее тут

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4🌚1💊1
Ты правильно используешь коллекции в Java?

Не все коллекции одинаково полезны, и неправильный выбор может увеличить нагрузку на CPU или память в 10 раз, даже не замечая этого. Если работаешь с большими коллекциями, это важно:

1. ArrayList

Идеально, когда:

Читаешь много, а пишешь мало.

Доступ к элементам по позиции (get(i)).

Почему? Внутри — массив. Чтение очень быстрое, но вставка или удаление в середине медленные, потому что нужно сдвигать элементы.

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

2. LinkedList

Идеально, когда:

Постоянно добавляешь или удаляешь элементы.

Не нужен прямой доступ к элементу по индексу.

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

Используй для: очередей, буферов или структур, где важен порядок, а не скорость доступа.

3. HashMap

Идеально, когда:

Нужно хранить пары ключ/значение.

Требуется быстрый доступ по ключу (как словарь).

Использует функцию хеширования для быстрого поиска. Если hashCode() реализован плохо, может работать медленно и потреблять больше памяти.

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

Перед оптимизацией спроси себя:

Много читаю и мало пишу? → ArrayList

Часто вставляю/удаляю? → LinkedList

Ищу по ключу? → HashMap

Нет универсально «лучшей» структуры. Есть та, которая подходит под твой способ доступа к данным.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍114
This media is not supported in your browser
VIEW IN TELEGRAM
Gitvizz превращает код в интерактивный граф

Терялся в собственном коде?

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

Посмотреть можно на gitvizz.com

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍4
Что такое String Pool

String Pool → это специальная область памяти внутри heap, где Java хранит строковые литералы.
Главная идея → повторное использование строк и экономия памяти.

Как это работает:

String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // true


s1 и s2 указывают на один и тот же объект в String Pool → дубликаты не создаются.

Но если сделать так:

String s3 = new String("Java");
System.out.println(s1 == s3); // false


new String() обходит пул и создаёт новый объект в heap.

Зачем это нужно:
→ Экономит память за счёт переиспользования неизменяемых строк.
→ Повышает производительность при повторных строковых значениях.
→ Безопасно для потоков, потому что строки immutable.

Как заставить строку из heap использовать пул?

Ответ:

s3 = s3.intern();


Метод intern() → добавляет строку в пул и возвращает ссылку на объект из пула.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍95
Топ-20 вопросов по микросервисам для Java-разработчиков

На Java67 вышла подборка самых частых вопросов по микросервисной архитектуре — от отличий монолита до тем вроде Docker, Kubernetes, API Gateway, CQRS и Saga-паттернов.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🤔1
Сценарный вопрос с реального интервью по Java/Spring Boot:

В контроллере вызывается метод сервиса, помеченный аннотацией @Transactional.
Этот метод не только сохраняет сущность, но и отправляет два письма: одно администратору, другое — пользователю, который сделал запрос.

Класс, отвечающий за отправку почты, помечен аннотацией @Async, но Spring всё равно выполняет его синхронно.
В итоге API обрабатывает запрос целых 12 секунд — очевидно, это неприемлемо.

Вопрос: почему так происходит и как это исправить?

Реальная причина:

Когда используется @Transactional, Spring создаёт прокси для транзакции.
Если внутри этого же контекста вызывается @Async-метод, то Spring не создаёт новый поток — потому что вызов происходит внутри того же прокси.

Иными словами, асинхронный код оказывается «заперт» внутри транзакции.

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

Как исправить:

Заменить прямой вызов отправки писем на event-publisher подход.

После сохранения запроса просто опубликовать событие, например DemoRequestCreatedEvent.

Асинхронные слушатели (@EventListener + @Async) будут обрабатывать отправку писем вне основной транзакции.

Что получаем:

Транзакция завершается за ~100 мс вместо 12 секунд.

API реагирует почти мгновенно.

Письма всё так же надёжно уходят в фоне.

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

Дополнительный вопрос:
Кроме событий, какие подходы ты используешь, чтобы отделить транзакционную логику (например, коммит в БД) от побочных эффектов вроде отправки писем или уведомлений?

@Java_Iibrary
👍92
This media is not supported in your browser
VIEW IN TELEGRAM
Хочешь сделать крутой GitHub-профиль?

На этом сайте собраны десятки классных README от разработчиков со всего мира. Можно смотреть код, вдохновляться, подхватывать идеи и оформить свой профиль так, чтобы он реально выделялся.

github.com/zzetao/awesome-github-profile

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍3
В Java есть одно зарезервированное слово, которое многие не замечают — yield.

Оно появилось в Java 13 вместе с switch expressions.

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

Пример:

int day = 2;

String result = switch (day) {
case 1 -> "Понедельник";
case 2 -> {
System.out.println("Обработка...");
yield "Вторник"; // значение, которое возвращается
}
default -> "Другой день";
};


yield — не то же самое, что break:

break просто прерывает выполнение;

yield возвращает значение блока в switch, который используется как выражение.

🌟

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍135
🔍Тестовое собеседование с Java-разработчиком из Мегафон уже завтра

15 октября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
📂 Мария Пивоварова, старший разработчик в Мегафон, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Мария будет комментировать каждый ответ респондента, чтобы дать понять, чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Марии

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot

Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Шаг за шагом проектируем сокращатель ссылок

В статье разбираем System Design на реальном примере = создаем свой сервис сокращения ссылок. Это классическая задача, которую часто дают на собеседованиях, и при этом отличная возможность понять, как устроен процесс проектирования систем: от постановки задачи до расчёта нагрузки и продумывания архитектуры.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
4
В Spring Boot можно включить «мягкое» завершение приложения, добавив в конфиг строку: "server.shutdown=graceful"

server:
shutdown: graceful

spring:
lifecycle:
timeout-per-shutdown-phase: 20s

# Сервер будет завершать работу корректно
# Он даст до 20 секунд на завершение всех запросов и бинов.


Это помогает избежать типичных проблем при остановке сервиса:

- Активные HTTP-запросы обрываются посреди выполнения
- Транзакции в базе откатываются неожиданно
- Потоки прерываются до завершения работы

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10👀3
6.851 MIT: Продвинутые структуры данных (весна'21)

Этот курс давно был у меня в списке рекомендаций. Разбор темы иерархии памяти там отлично подан в контексте cache-oblivious алгоритмов.

https://courses.csail.mit.edu/6.851/spring21/

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
Сборщик мусора (Garbage Collector, GC) сильно эволюционировал со временем. Сегодня есть несколько вариантов, и ты можешь выбрать тот, что подходит под твои нужды. Смотри:

- Serial GC (олдскул)

Самый простой и древний.
Один поток, останавливает всё приложение на время очистки памяти.
Подходит для мелких приложений, CLI-инструментов или систем с маленьким heap (пара десятков мегабайт).

- Parallel GC

По сути, тот же Serial, но работает в несколько потоков.
Паузы всё ещё есть, но они короче.
Хорош для batch-задач или сервисов, где короткая остановка не критична.

- G1 GC (Garbage First)

С Java 9 — сборщик по умолчанию.
Делит heap на регионы и чистит только самые “грязные”.
Даёт меньше пауз и предсказуемее поведение.
Оптимальный выбор для большинства продакшен-приложений: Spring, микросервисы и т. д.

- ZGC (Z Garbage Collector)

Паузы меньше 1 мс даже при heap в сотни гигабайт.
Работает почти полностью конкурентно, фактически в реальном времени.
Подходит для систем, которые не могут останавливаться: трейдинг, онлайн-игры, API с высокой доступностью.

- Shenandoah GC

Похож на ZGC, но реализован по-другому (Red Hat).
Тоже стремится к минимальным паузам, отлично чувствует себя на Linux.
Менее популярный, но стабильный вариант.

Что выбрать?

Небольшие приложения → Serial

Batch-процессы → Parallel

Веб-сервисы, микросервисы → G1

Реальное время, критичная задержка → ZGC или Shenandoah

GC уже давно не “та самая штука, что стопит Java”, а гибкий инструмент, который можно подобрать под задачу.
И от этого выбора реально зависит будет твое приложение тормозить… или летать

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍102
Transactions_and_Concurrency_Control.pdf
6.3 MB
Если ты работаешь с Java, очень советую почитать последнее издание “Troubleshooting Java”

В книге куча практических вещей: от лучших практик отладки до логирования, трейсинга, телеметрии, модели памяти Java, предотвращения дедлоков, профайлинга и сэмплинга.

Отличное чтиво, если хочешь реально понимать, что происходит под капотом JVM и как быстро находить проблемы в проде.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Может ли статический блок выбросить исключение?


У тебя есть класс, который инициализирует какой-то критически важный статический ресурс внутри статического блока. В процессе инициализации может произойти ошибка, и выбросится исключение. Что произойдет, если исключение будет выброшено из статического инициализатора? Какую ошибку в итоге выбросит JVM, и в каком состоянии останется класс после этого?
Подсказка → Если из статического блока выбрасывается исключение, инициализация класса завершается с ошибкой.

Есть ли в Java концепция выбрасывания исключений конструктором?


Ты создаешь класс DatabaseConnection. В конструкторе происходит попытка установить соединение с базой данных, и если это не удается, выбрасывается SQLException. Что произойдет с памятью, выделенной под объект DatabaseConnection, если конструктор выбросит исключение? Можно ли использовать объект после того, как исключение было выброшено?
Подсказка → Конструкторы могут (и часто должны) выбрасывать исключения, если объект невозможно создать в корректном состоянии.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
2025/10/17 15:38:54
Back to Top
HTML Embed Code: