Будет ли ленивым Bean с аннотацией Lazy, если он внедряется в другой Bean в Spring?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
@Lazy Bean при внедрении в другой Bean
Ответ: Да, @Lazy bean останется ленивым (не будет создан сразу) даже при внедрении в другой Bean, при условии правильного использования.
Однако есть важное уточнение: Spring создаёт прокси-объект для ленивого бина, чтобы отложить его инициализацию.
Основной механизм
Когда бин помечен как @Lazy, Spring создаёт прокси, который перехватывает первый вызов метода и только тогда инициализирует реальный бин.
@Component
@Lazy
public class LazyBean {
public LazyBean() {
System.out.println("LazyBean создан");
}
public void doSomething() {
System.out.println("LazyBean работает");
}
}
@Component
public class ConsumerBean {
private final LazyBean lazyBean;
// Внедрение через конструктор
public ConsumerBean(LazyBean lazyBean) {
System.out.println("ConsumerBean создан");
this.lazyBean = lazyBean; // Это будет прокси, не реальный объект
}
public void useBean() {
lazyBean.doSomething(); // Здесь инициализируется реальный LazyBean
}
}
Вывод консоли:
ConsumerBean создан
// ... время прошло, никаких инициализаций
LazyBean работает
LazyBean создан // Только когда вызвали метод
Важные детали
- Внедрение конструктора + @Lazy = Ленивость сохраняется
@Component
public class ServiceA {
private final LazyServiceB serviceB;
public ServiceA(@Lazy LazyServiceB serviceB) { // Можно и здесь аннотировать
this.serviceB = serviceB;
}
}
@Component
public class LazyServiceB {
public LazyServiceB() {
System.out.println("ServiceB инициализирован");
}
}
- Внедрение через сеттер + @Lazy = Ленивость сохраняется
@Component
public class ConfigService {
private LazyDataSource dataSource;
@Autowired
public void setDataSource(@Lazy LazyDataSource dataSource) {
this.dataSource = dataSource;
}
}
- Внедрение поля + @Lazy = Нужна явная аннотация
@Component
public class FieldInjectService {
@Autowired
@Lazy // Важно! Нужна явная аннотация на поле
private LazyBean lazyBean;
}
Когда ленивость НЕ будет сохранена
Если dependency является Singleton и используется в конструкторе без @Lazy:
@Component
public class EagerConsumer {
// ✗ LazyBean будет инициализирован сразу, несмотря на @Lazy на самом бине
public EagerConsumer(LazyBean lazyBean) { // Без @Lazy параметра
System.out.println("EagerConsumer инициализирован");
}
}
В этом случае Spring игнорирует @Lazy на LazyBean и инициализирует его сразу.
Правильный способ гарантировать ленивость
@Configuration
public class AppConfig {
@Bean
@Lazy
public ExpensiveService expensiveService() {
System.out.println("ExpensiveService инициализирован");
return new ExpensiveService();
}
@Bean
public MainService mainService(@Lazy ExpensiveService expensiveService) {
return new MainService(expensiveService);
}
}
public class MainService {
private final ExpensiveService expensiveService;
public MainService(ExpensiveService expensiveService) {
this.expensiveService = expensiveService; // Прокси
}
public void process() {
expensiveService.execute(); // Инициализация происходит здесь
}
}
Использование ObjectProvider для управления ленивостью
@Component
public class FlexibleConsumer {
private final ObjectProvider<LazyBean> lazyBeanProvider;
public FlexibleConsumer(ObjectProvider<LazyBean> lazyBeanProvider) {
this.lazyBeanProvider = lazyBeanProvider;
}
public void useWhenNeeded() {
LazyBean bean = lazyBeanProvider.getObject(); // Инициализируется здесь
bean.doSomething();
}
}
Вывод
@Lazy bean останется ленивым при внедрении в другой Bean, но Spring создаст прокси для отложенной инициализации. Реальный объект будет создан только при первом обращении к его методам. Это полезно для экономии памяти при запуске приложения, когда некоторые компоненты инициализируются редко.