【问题标题】:How to inject ApplicationContext from Component?如何从组件中注入 ApplicationContext?
【发布时间】:2020-02-27 13:31:39
【问题描述】:

我想在 MyComponent 类中使用 ApplicationContext 实例。当我尝试自动装配时,Spring 在启动时初始化我的组件时出现空指针异常。

有没有办法在 MyComponent 类中自动装配 ApplicationContext?

@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
    }

}

【问题讨论】:

标签: java spring-boot


【解决方案1】:

如果您想确保您的依赖项(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需要先创建bean(MyComponent)然后设置字段的值,所以在构造函数中,你的字段的值为null

【讨论】:

    【解决方案2】:

    问题在于 MyComponent 构造函数在 Spring 自动装配 ApplicationContext 之前被调用。 这里有两种方法:

    • 在构造函数中注入依赖(better way):

    @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(...);
        }
    }
    

    我认为它可能不太安全,但它提供了更易读的代码。


    哦,这就是我个人使用的方式,lombok。 它使得几乎没有样板代码,直到您真的需要在构建时执行一些操作或有一些不可自动装配的字段。 :D

    @Component
    @AllArgsConstructor(onConstructor_ = @Autowired)
    public class MyComponent {
        private final ApplicationContext ctx;
    
        @PostConstruct
        private void init() {
            ctx.getBean(...);
        }
    }
    

    【讨论】:

    • 哦,我太慢了 19 分钟。 ':D
    猜你喜欢
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2019-02-04
    • 2012-03-28
    • 1970-01-01
    • 2012-06-05
    相关资源
    最近更新 更多