hellzone
hellzone

Reputation: 5236

How to inject ApplicationContext from Component?

I want to use ApplicationContext instance inside MyComponent class. When I try to autowire, I am getting null pointer exception when Spring initializing my components on startup.

Is there any way to autowire ApplicationContext inside MyComponent class?

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

}

Upvotes: 1

Views: 3167

Answers (2)

Xobotun
Xobotun

Reputation: 1371

The problem is that the MyComponent constructor is called before Spring autowires ApplicationContext. Here are two ways:

• Inject the dependency in constructor (better way):

@Component
public class MyComponent{
    private final ApplicationContext ctx;

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

• Or inject it via field injection (worse way) and use @PostConstruct lifecycle annotation:

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

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

It may be less safe, but it provides more readable code, I think.


Oh, and there's the way I personally use, with lombok. It makes there's almost no boilerplate code until you really need to do some actions at construction time or have some non-autowireable fields. :D

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

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

Upvotes: 2

Vüsal
Vüsal

Reputation: 2706

If you want to make sure, that your dependency (bean) is initialized and ready in the constructor you should use constructor injection, not field injection:

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

Another approach is to use @PostConstruct like below:

@Component
public class MyComponent {

    @Autowired
    ApplicationContext ctx;

    public MyComponent(){

    }

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

}

You get NPE because spring needs to first create the bean (MyComponent) and then set the field's value, so in the constructor, the value of your field is null.

Upvotes: 6

Related Questions