Сохраняется ли ленивая инициализация бина с аннотацией @Lazy в Spring, если он внедряется в другой бин?

«Сохраняется ли ленивая инициализация бина с аннотацией @Lazy в Spring, если он внедряется в другой бин?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Не всегда. Ленивая инициализация (@Lazy) сохраняется только если и принимающий бин (клиент), и контекст внедрения настроены соответствующим образом. В противном случае Spring создаст зависимый бин во время создания бина-клиента.

Правила и сценарии:

  1. Внедрение через конструктор (по умолчанию не ленивое): Если бин-клиент не является @Lazy, Spring создаст ленивый бин-зависимость во время создания клиента, так как ему нужен готовый аргумент для конструктора.

    @Component
    class Client {
        private final Service service;
        // Service будет создан НЕМЕДЛЕННО при создании Client!
        public Client(@Lazy Service service) { 
            this.service = service;
        }
    }
  2. Внедрение через поле или setter-метод: Ленивая зависимость будет создана только при первом обращении к полю/методу.

    @Component
    class Client {
        @Autowired
        @Lazy // Прокси внедряется сразу, реальный объект Service создастся при первом вызове
        private Service service;
    }
  3. Полностью ленивая цепочка: Чтобы и клиент, и его зависимость инициализировались лениво, нужно аннотировать @Lazy оба бина.

    @Configuration
    class AppConfig {
        @Bean
        @Lazy
        public Service service() {
            return new Service();
        }
    
        @Bean
        @Lazy // Client и его зависимость Service создадутся только при первом обращении
        public Client client(Service service) {
            return new Client(service);
        }
    }

Ключевой вывод: Аннотация @Lazy создаёт прокси-объект. Момент инициализации реального объекта зависит от способа и контекста внедрения.