Использование аннотаций Spring @Lazy и @PostConstruct

У меня есть следующие классы:

@Repository
class A {

    public void method1() {
        ...
    }
}

@Component
class B implements C {

    @Autowired
    @Lazy
    private A a;

    public void method2() {
        a.method1();
    }
}

@Component
class D {

    @Autowired
    private List<C> c;

    @PostConstruct
    public void method3() {
        // iterate on list c and call method2()
    }
}

Предположим, что Spring инициализирует bean-компоненты следующим образом:
1. Создается первый bean-компонент B. При создании компонента B поле a не будет инициализировано из-за аннотации @Lazy.
2. Создается следующий компонент D. Затем будет выполнен method3(), поскольку он помечен @PostConstruct, но компонент A еще не затронут Spring. Итак, когда будет вызываться a.method1(), Spring создаст bean-компонент A и вставит его в поле a или выдаст NullPointerException?


person rohanagarwal    schedule 03.01.2017    source источник
comment
Вы пытались запустить ту же настройку?   -  person Arpit Aggarwal    schedule 03.01.2017
comment
@Arpit Да, я это сделал, и он ввел A в a. Но я не могу гарантировать, придет ли Spring сначала к A или к D. Если он сначала придет к A, он сможет внедрить A в a при выполнении method3(). Если сначала дело доходит до D, то может возникнуть проблема.   -  person rohanagarwal    schedule 03.01.2017


Ответы (1)


Вы должны понимать, что происходит, когда вы указываете @Lazy как часть инъекции. Согласно документации:

Помимо своей роли для инициализации компонента, аннотация @Lazy может также размещаться в точках внедрения, отмеченных @Autowired или @Inject. В этом контексте это приводит к внедрению прокси-сервера отложенного разрешения.

Это означает, что при запуске Spring будет внедрять экземпляр прокси-класса вместо экземпляра класса A. Прокси-класс — это автоматически сгенерированный класс, который имеет тот же интерфейс, что и класс A. При первом вызове любого метода proxy создаст экземпляр класса A внутри себя. После этого все вызовы методов будут перенаправлены на этот экземпляр класса A внутри прокси.

Так что нет причин бояться каких-либо проблем.

person Ken Bekov    schedule 03.01.2017
comment
Я проверил это, и да, это работает. Я проверил, что NPE не будет выброшен, и (экземпляр A) будет создан при первом вызове. Добавлено небольшое пояснение о прокси, чтобы было понятнее: прокси — это суррогатный объект или заполнитель для другого объекта для управления доступом к нему. Поскольку прокси-сервер находится между вызывающей стороной объекта и самим реальным объектом, он может решить предотвратить вызов реального (или целевого) объекта или сделать что-то до вызова целевого объекта. - person rohanagarwal; 03.01.2017