Reputation: 5236
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
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
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