SpringBoot ContextLoaderListener、Servlet
一、问题
SpringBoot v2.3.2中使用 ContextLoaderListener.getCurrentWebApplicationContext() 获取WebApplicationContext为空

二、原因
要使用这个API我们首先得明确它是个什么玩意儿,ContextLoaderListener 实际上就是一个监听器,作用就是启动web容器时,自动装配ApplicationContext的配置信息,它实现了ServletContextListener(三大生命周期监听之一);
摘个图

Spring实现了Tomcat提供的ServletContextListener接口,写了一个监听器来监听项目启动,一旦项目启动,会触发ContextLoaderListener中的特定方法 contextInitialized
也就是说Tomcat的ServletContext创建时,会调用ContextLoaderListener的 contextInitialized(),这个方法内部的initWebApplicationContext()就是用来初始化Spring的IOC容器的。
- ServletContext对象是Tomcat的;
- ServletContextListener是Tomcat提供的接口;
- ContextLoaderListener是Spring写的,实现了ServletContextListener;
- Spring自己写的监听器,用来创建Spring IOC容器;
好,现在我们知道它是个干什么的了,对,它就是用来初始化IOC容器的,我们都知道IOC里存放的我们的Bean对象,那么自然而然肯定有对应的方法来获取我们所需要的Bean对象,那么getCurrentWebApplicationContext()方法就派上用场了。
但是为什么在我们项目中使用这个方法返回的对象是null呢?
首先我们得看看这是什么时候的技术?依赖于什么?
查找资料后明白了ContextLoaderListener如果要实现它应有的功能,是需要在web.xml中配置的;而SpringBoot中无论是以main方法还是spring-boot:run的方式执行都不跑SpringBootServletInitializer中的onStartup导致ContextLoaderListener没有执行。
附公司大佬的解释:
- ContextLoader是servlet2.5那个时代的产物,它需要靠web.xml里去拉起servletcontext在启动的时候去初始化RootWebApplicationContext(就是对上面的一个总结);
- 在servlet3.0后被SpringBoot自己给干掉了;
惭愧惭愧,本人入行这么些时间,都没有玩过有web.xml的项目,算是入行比较晚。
三、解决
-
最基本最官方的一个解决方案把,写一个类去实现ApplicationContextAware 并实现它的setApplicationContext方法,将方法中的参数ApplicationContext 赋值给我们自己创建的静态变量,之后使用静态变量来获取我们的Bean容器即可,如下文:
@Component @Lazy(false) public class ApplicationContextRegister implements ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextRegister.class); private static ApplicationContext APPLICATION_CONTEXT; /** * 设置spring上下文 * * @param applicationContext spring上下文 * @throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { LOGGER.debug("ApplicationContext registed-->{}", applicationContext); APPLICATION_CONTEXT = applicationContext; } public static ApplicationContext getApplicationContext() { return APPLICATION_CONTEXT; } } -
现在很多市场上的工具类也都有这个功能,类似hutool中的SpringUtil.getBean()方法
/** * 通过class获取Bean * * @param <T> Bean类型 * @param clazz Bean类 * @return Bean对象 */ public static <T> T getBean(Class<T> clazz) { return getBeanFactory().getBean(clazz); }
标题:SpringBoot ContextLoaderListener、Servlet
作者:zzzzchen
地址:https://dczzs.com/articles/2022/05/05/1651751196861.html