背景
传统的tomcat方式运行的项目改造SpringBoot方式,遇到listener和springContext加载的关系问题。
传统项目配置listener方式在web.xml中,tomcat启动是会检查web.xml文件进行加载,如下:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.tx.MonitoerLoaderListener</listener-class>
</listener>
在项目中一般都会写个静态的公共类SpringContextHolder来获取bean,如下:
public class SpringContextHolder implements ApplicationContextAware{
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
}
在tomcat启动时会扫描并调用实现了ApplicationContextAware接口的setApplicationContext方法从而设置SpringContextHolder。这个会在listener加载前先执行。所以listener中可以直接使用传递SpringContextHolder的getBean(xx)方法。
项目改造成SpringBoot后,通过@ServletComponentScan注册listener,每次都是先加载listener后加载ApplicationContextAware一直无法获取到SpringContext。
springBoot改造方案
通过使用spring-web自带的类WebApplicationContextUtils的getWebApplicationContext(ServletContext xx)会返回一个WebApplicationContext,如下:
@WebListener
public class BootServiceListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
if(!SpringContextHolder.hasContext())
SpringContextHolder.setSpringContext(wac);
}
配合@ServletComponentScan("xxx.xx.config")即可。
作者:Owen Jia,推荐关注他的博客:Owen Blog 。