← Назад к вопросам

Будет ли ленивым Bean с аннотацией Lazy, если он внедряется в другой Bean в Spring?

2.0 Middle🔥 171 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

@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 создан  // Только когда вызвали метод

Важные детали

  1. Внедрение конструктора + @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 инициализирован");
    }
}
  1. Внедрение через сеттер + @Lazy = Ленивость сохраняется
@Component
public class ConfigService {
    private LazyDataSource dataSource;
    
    @Autowired
    public void setDataSource(@Lazy LazyDataSource dataSource) {
        this.dataSource = dataSource;
    }
}
  1. Внедрение поля + @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 создаст прокси для отложенной инициализации. Реальный объект будет создан только при первом обращении к его методам. Это полезно для экономии памяти при запуске приложения, когда некоторые компоненты инициализируются редко.