Как добавить ApplicationContext из компонента? - PullRequest
1 голос
/ 01 ноября 2019

Я хочу использовать экземпляр ApplicationContext внутри класса MyComponent. Когда я пытаюсь выполнить автоматическое подключение, я получаю исключение нулевого указателя, когда Spring инициализирует мои компоненты при запуске.

Есть ли способ автоматического подключения ApplicationContext внутри класса MyComponent?

@SpringBootApplication
public class SampleApplication implements CommandLineRunner {

    @Autowired
    MyComponent myComponent;

    @Autowired
    ApplicationContext context;  //Spring autowires perfectly at this level

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

}


@Component
public class MyComponent{

    @Autowired
    ApplicationContext ctx;

    public MyComponent(){
        ctx.getBean(...) //throws null pointer
    }

}

Ответы [ 2 ]

3 голосов
/ 01 ноября 2019

Если вы хотите убедиться, что ваша зависимость (bean) инициализирована и готова в конструкторе, вы должны использовать инжектор конструктора, а не поле:

    @Autowired
    public MyComponent(ApplicationContext ctx){
        ctx.getBean(...) // do something
    }

Другой подход заключается в использовании @PostConstruct как показано ниже:

@Component
public class MyComponent {

    @Autowired
    ApplicationContext ctx;

    public MyComponent(){

    }

    @PostConstruct
    public void init() {
        ctx.getBean(...); // do something
    }

}

Вы получаете NPE, потому что Spring должен сначала создать компонент (MyComponent), а затем установить значение поля, поэтому в конструкторе значениевашего поля null.

1 голос
/ 01 ноября 2019

Проблема заключается в том, что конструктор MyComponent вызывается до автосинхронизации Spring ApplicationContext. Вот два способа:

• Ввести зависимость в конструктор ( лучший способ ):

@Component
public class MyComponent{
    private final ApplicationContext ctx;

    @Autowired
    public MyComponent(ApplicationContext ctx) {
        this.ctx = ctx;
        ctx.getBean(...);
    }
}

• Или внедрить ее с помощью инъекции поля (худший способ) и использовать@PostConstruct аннотация жизненного цикла:

@Component
public class MyComponent {
    @Autowired
    private ApplicationContext ctx; // not final

    @PostConstruct
    private void init() {
        ctx.getBean(...);
    }
}

Возможно, она менее безопасна, но, по-моему, она обеспечивает более читаемый код.


О, и я лично использую этот способ,с ломбок . Это делает практически нет стандартного кода, пока вам действительно не нужно будет выполнять какие-то действия во время создания или иметь некоторые неавтоматизируемые поля. : D

@Component
@AllArgsConstructor(onConstructor_ = @Autowired)
public class MyComponent {
    private final ApplicationContext ctx;

    @PostConstruct
    private void init() {
        ctx.getBean(...);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...