Ответ
Ленивый (lazy) бин — это компонент Spring, инициализация которого откладывается до момента его первого запроса, а не выполняется при запуске контекста приложения.
Зачем это нужно?
- Оптимизация старта: Ускоряет запуск приложения, если бин ресурсоемкий (например, подключается к внешним сервисам, загружает большие файлы).
- Условная инициализация: Полезен, когда бин требуется не во всех сценариях работы приложения.
Как объявить?
Используйте аннотацию @Lazy:
@Component
@Lazy // Инициализация произойдет только при первом инжекте или вызове
public class HeavyResourceService {
public HeavyResourceService() {
// Долгая инициализация
System.out.println("HeavyResourceService создан!");
}
}
Важные детали:
- Поведение по умолчанию: Бины в Spring —
eager(жадные), они создаются при старте контекста. - Область применения:
@Lazyможно ставить на класс (@Component,@Serviceи т.д.) или на метод, объявляющий бин (@Bean). - Зависимости: Если ленивый бин является зависимостью другого бина, аннотацию
@Lazyнужно также указать и в точке инжекции (в поле, конструкторе или методе-сеттере), иначе Spring создаст его при создании зависимого бина. - Скоупы: Для бинов со скоупом
prototypeповедение по умолчанию всегда аналогично ленивой инициализации.
Ответ 18+ 🔞
А, ну вот, смотри, ленивый бин в Спринге — это как тот твой друг, который всегда говорит «щас, щас приду», а на деле вылезает из дома, только когда все уже в баре сидят и третью кружку допивают. Понимаешь? Это бин, который нихуя не делается, пока его впервые реально не попросят.
А нахуя это вообще надо, спросишь ты?
- Чтобы приложение не тупило на старте. Представь, у тебя есть сервис, который подключается к какому-нибудь древнему медленному API, или там гигабайтный конфиг грузит. Зачем его поднимать сразу, если пользователь, может, даже на эту страницу не зайдет? Пусть валяется, пока не понадобится.
- Если он нужен не всегда. Ну, типа, функционал «отправить отчет бухгалтерии в налоговую» — его раз в квартал дергают, а приложение-то крутится каждый день. Зачем его грузить?
Как его такого объявить?
Вешаешь волшебную аннотацию @Lazy, и всё.
@Component
@Lazy // Вот этот флажок. Теперь он будет сидеть в углу, пока к нему не обратятся.
public class HeavyResourceService {
public HeavyResourceService() {
// Тут типа долгая инициализация, все дела
System.out.println("HeavyResourceService создан! Ну наконец-то, блядь.");
}
}
А теперь, блядь, важные нюансы, чтобы не обосраться:
- По дефолту все жадные. Спринг как голодный студент — хватает все бины сразу и пытается их скормить контексту.
@Lazyделает бин нежадным, похуистичным. - Куда вешать можно. Или прямо на класс (
@Component,@Service), или на метод с@Beanв конфиге. Где удобнее. - Вот это, блядь, ключевое — зависимости! Допустим, у тебя есть
UserService, который использует этот твой ленивыйHeavyResourceService. Так вот, мало@Lazyна самомHeavyResourceServiceнавесить. Надо его и вUserServiceпри инжекте тоже как ленивую зависимость пометить! Иначе Спринг такой: «Ага, создаюUserService, а для него нуженHeavyResourceService... Так, а он у нас ленивый... Ну похуй, создам сейчас же!». И вся оптимизация коту под хвост. - С бинами-прототипами (prototype) вообще отдельная история. Они по умолчанию и так ведут себя как ленивые, потому что их создают новый экземпляр на каждый запрос. Так что там
@Lazyобычно не нужен.
Короче, инструмент охуенный, но, как и всё в Спринге, требует, чтобы ты немного подумал головой, а не просто аннотации тыкал. Иначе получишь не оптимизацию, а ебучую головную боль, когда что-то не создалось тогда, когда ты ожидал.