Как работают Spring Boot Autowired и Post Construct? - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть три класса следующим образом -

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@Component
public class Test {
    @Autowired
    Test2 test2;

    @PostConstruct
    public void sayHi(){
        System.out.println("Hello World");
        test2.SayHello();
    }

    public void printMe(){
        System.out.println("print me is called in Bean B");
    }
}

@Component
public class Test2 {
    @Autowired
    Test test;

    @PostConstruct
    public void SayHello(){
        System.out.println("Test2");
        test.sayHi();
    }
}

Теперь этот исключение выдает -

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'test2': Invocation of init method failed; nested exception is java.lang.NullPointerException

Однако, если я изменю класс Test2 следующим образом -

    @Component
public class Test2 {
    @Autowired
    Test test;

    @PostConstruct
    public void SayHello(){
        System.out.println("Test2");
        test.printMe();
    }
}

Этот работает. Если он должен был потерпеть неудачу, то почему он не потерпел неудачу в обоих случаях? Или, если это должно было произойти, почему это не удалось в обоих случаях?

Как работает инициализация Spring с автопроводом и пост-конструктором?

1 Ответ

1 голос
/ 14 февраля 2020

Spring создает экземпляры bean-компонентов и внедряет для них зависимости в соответствии с их отношением.
Spring гарантирует, что объявленному bean-компоненту будут введены / установлены все его зависимости до того, как он вызовет свой аннотированный метод @PostConstruct.

Вот отношения между бобами:

Test --uses -> Test2

Test2 --uses -> Test

Вот как это работает:

1) Spring создает экземпляр компонента, а затем другого, не вводя их зависимости. Пока порядок не имеет значения.
2) Spring вводит зависимости для первого компонента. Так как здесь зависимости являются двунаправленными, Spring произвольно решает, какой компонент должен обрабатывать первый. В вашем случае, согласно вашей ошибке, Spring сначала обрабатывает Test2.
3) Spring вызывает метод @PostConstruct компонента Test2 после установки его зависимостей.
Метод, который вы определили, вызывает метод бин Test, использующий поле зависимости (Test2 test2). Но поскольку зависимости этого bean-компонента еще не установлены, это поле имеет значение null, и доступ к нему вызывает NPE.

В вашем рабочем случае вы вызываете из Test2 метод Test, который не ссылается на его поля зависимостей.

Обратите внимание, что циклические c зависимости обычно не рекомендуются. Вот иллюстрация проблем, которые могут возникнуть.
Когда вы не можете удалить их, вы должны, по крайней мере, избегать вызова другого компонента в методе @PostConstruct, потому что он наносит ущерб работе, выполняемой контейнером, чтобы прервать цикл во время их инициализация.

...