Reputation: 65
Today, I encountered a bug in my spring-boot project.
In my code, I want to get the ApplicationContext
, but it's null
, so I couldn't use getBean()
.
This is Application.java
for config:
@SpringBootApplication
@EnableAspectJAutoProxy
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(Application.class);
}
@Bean
public ServletRegistrationBean readHitchEventServletBean() {
ServletRegistrationBean readHitchEventServletBean =
new ServletRegistrationBean();
readHitchEventServletBean.setServlet(new ReadHitchEventServlet());
readHitchEventServletBean.setLoadOnStartup(5);
return readHitchEventServletBean;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Then the servlet :
@Component
public class ReadHitchEventServlet extends HttpServlet implements ApplicationContextAware {
private static final long serialVersionUID = 1L;
private static ApplicationContext applicationContext;
@SuppressWarnings("static-access")
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
@Override
public void init() {
getBean("heheda");
}
}
And I am getting the below error:
java.lang.NullPointerException: null
at com.gdut.dongjun.ActiveSwitchThread.getBean(ReadHitchEventServlet.java:126) ~[classes/:na]
at com.gdut.dongjun.ActiveSwitchThread.<init>(ReadHitchEventServlet.java:66) ~[classes/:na]
at com.gdut.dongjun.ReadHitchEventServlet.init(ReadHitchEventServlet.java:56) ~[classes/:na]
at javax.servlet.GenericServlet.init(GenericServlet.java:158) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1231) [tomcat-embed-core-8.0.23.jar:8.0.23]
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1034) [tomcat-embed-core-8.0.23.jar:8.0.23]
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4914) [tomcat-embed-core-8.0.23.jar:8.0.23]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedContext.deferredLoadOnStartup(TomcatEmbeddedContext.java:66) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.startConnector(TomcatEmbeddedServletContainer.java:209) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:152) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:288) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:141) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:483) [spring-context-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.jrLockAndRefresh(AbstractApplicationContext.java) [spring-context-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java) [spring-context-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946) [spring-boot-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at com.gdut.dongjun.Application.main(Application.java:282) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_79]
at org.springframework.boot.maven.RunMojo$LaunchRunner.run(RunMojo.java:418) [spring-boot-maven-plugin-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at java.lang.Thread.run(Thread.java:745) [na:na]
How do I fix it?
Upvotes: 1
Views: 11354
Reputation: 2996
On line:
readHitchEventServletBean.setServlet(new ReadHitchEventServlet());
You are creating a new instance of the servlet object that is not a Spring Bean and thus it is not being wired-up correctly. If you want to do it this way, consider doing the following:
Application.java:
@Bean
public ServletRegistrationBean readHitchEventServletBean(ApplicationContext applicationContext) {
ServletRegistrationBean readHitchEventServletBean = new ServletRegistrationBean();
readHitchEventServletBean.setServlet(new ReadHitchEventServlet(applicationContext));
readHitchEventServletBean.setLoadOnStartup(5);
return readHitchEventServletBean;
}
ReadHitchEventServlet.java:
public class ReadHitchEventServlet extends HttpServlet {
private final ApplicationContext applicationContext;
ReadHitchEventServlet(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void init() {
applicationContext.getBean("heheda");
}
}
Or even better would be to just leave out the ApplicationContext entirely and just wire the bean you ultimate want.
Application.java:
@Bean
public ServletRegistrationBean readHitchEventServletBean(Heheda heheda) {
ServletRegistrationBean readHitchEventServletBean = new ServletRegistrationBean();
readHitchEventServletBean.setServlet(new ReadHitchEventServlet(heheda));
readHitchEventServletBean.setLoadOnStartup(5);
return readHitchEventServletBean;
}
ReadHitchEventServlet.java:
public class ReadHitchEventServlet extends HttpServlet {
private final Heheda heheda;
ReadHitchEventServlet(Heheda heheda) {
this.heheda = heheda;
}
@Override
public void init() {
// do something with heheda
}
}
Upvotes: 0
Reputation: 1252
It would be good to have a separate class which implements ApplicationContextAware to provide application context to required classes. The problem here appears to be Spean bean life cycle and servlet container life cycle performing different operations.
i.e init can be called before context could be set by spring.
Upvotes: 2