Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответ
@PreDestroy — это аннотация из JSR-250 (Java annotation для управления жизненным циклом), которая используется в Spring для обозначения метода, который должен быть вызван перед тем, как бин будет удалён из контекста приложения и сборен сборщиком мусора.
Основное назначение
@PreDestroy выполняет функцию очистки ресурсов (cleanup) и graceful shutdown бина. Это критично для:
- Закрытия соединений с БД
- Освобождения сокетов и сетевых ресурсов
- Сохранения состояния перед завершением
- Отписки от событий/слушателей
- Корректного завершения фоновых потоков
Жизненный цикл бина со @PreDestroy
Полный цикл выглядит так:
- @PostConstruct → инициализация бина (вызывается после внедрения зависимостей)
- Бин работает в контексте приложения
- @PreDestroy → очистка перед удалением
- Бин удаляется из памяти
Пример использования
import javax.annotation.PreDestroy;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
public class DatabaseConnectionPool {
private ExecutorService threadPool;
private Connection connection;
@PostConstruct
public void init() {
// Инициализация при создании бина
threadPool = Executors.newFixedThreadPool(10);
connection = createDatabaseConnection();
System.out.println("Connection pool initialized");
}
@PreDestroy
public void cleanup() {
// Очистка перед удалением
System.out.println("Cleaning up resources...");
if (threadPool != null && !threadPool.isShutdown()) {
threadPool.shutdown();
try {
threadPool.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
threadPool.shutdownNow();
Thread.currentThread().interrupt();
}
}
if (connection != null) {
try {
connection.close();
System.out.println("Database connection closed");
} catch (SQLException e) {
System.err.println("Error closing connection: " + e.getMessage());
}
}
}
private Connection createDatabaseConnection() {
// Создание подключения
return null; // для примера
}
}
Практический пример с REST сервисом
@Component
public class HttpClientManager {
private HttpClient httpClient;
private ScheduledExecutorService scheduler;
@PostConstruct
public void initialize() {
httpClient = HttpClient.newHttpClient();
scheduler = Executors.newScheduledThreadPool(5);
// Запуск периодической очистки кэша
scheduler.scheduleAtFixedRate(
this::cleanCache,
0, 1, TimeUnit.MINUTES
);
System.out.println("HTTP client initialized");
}
@PreDestroy
public void shutdown() {
System.out.println("Shutting down HTTP client...");
// Остановка scheduler
scheduler.shutdownNow();
// Закрытие HTTP клиента
if (httpClient != null) {
try {
// Некоторые реализации HttpClient требуют явного закрытия
System.out.println("HTTP client closed");
} catch (Exception e) {
System.err.println("Error during shutdown: " + e.getMessage());
}
}
}
private void cleanCache() {
System.out.println("Cache cleaned");
}
}
Важные аспекты
Когда вызывается:
- При остановке Spring контекста (shutdown)
- При удалении singleton бина
- При закрытии ApplicationContext
Ограничения и особенности:
- Метод не должен иметь параметров
- Метод должен быть public или package-private
- В scope=prototype бины @PreDestroy может не вызваться (Spring не отслеживает их удаление)
- Исключения в @PreDestroy могут помешать полной очистке других бинов
Best practices:
- Всегда обрабатывай исключения в @PreDestroy
- Убедись, что cleanup идемпотентен (можно вызвать дважды безопасно)
- Логируй что и когда закрывается для дебага утечек ресурсов
- Используй try-finally или try-with-resources где возможно
- Не полагайся на порядок вызова @PreDestroy для разных бинов
Альтернативы
destroyMethodв @Bean аннотации- Реализация
DisposableBeanинтерфейса (устаревший подход) @EventListener(ApplicationEvent.ContextClosedEvent.class)
@PreDestroy — это essential инструмент для правильного управления ресурсами и предотвращения утечек памяти в Spring приложениях.