目录

大橙子

VX:ZzzChChen
Phone:13403656751
Email:zxydczzs@gmail.com

X

SpringBoot ContextLoaderListener、Servlet

一、问题

SpringBoot v2.3.2中使用 ContextLoaderListener.getCurrentWebApplicationContext() 获取WebApplicationContext为空

image.png

二、原因

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

摘个图

Spring实现了Tomcat提供的ServletContextListener接口,写了一个监听器来监听项目启动,一旦项目启动,会触发ContextLoaderListener中的特定方法 contextInitialized

也就是说Tomcat的ServletContext创建时,会调用ContextLoaderListener的 contextInitialized(),这个方法内部的initWebApplicationContext()就是用来初始化Spring的IOC容器的。

  1. ServletContext对象是Tomcat的;
  2. ServletContextListener是Tomcat提供的接口;
  3. ContextLoaderListener是Spring写的,实现了ServletContextListener;
  4. Spring自己写的监听器,用来创建Spring IOC容器;

好,现在我们知道它是个干什么的了,对,它就是用来初始化IOC容器的,我们都知道IOC里存放的我们的Bean对象,那么自然而然肯定有对应的方法来获取我们所需要的Bean对象,那么getCurrentWebApplicationContext()方法就派上用场了。

但是为什么在我们项目中使用这个方法返回的对象是null呢?

首先我们得看看这是什么时候的技术?依赖于什么?

查找资料后明白了ContextLoaderListener如果要实现它应有的功能,是需要在web.xml中配置的;而SpringBoot中无论是以main方法还是spring-boot:run的方式执行都不跑SpringBootServletInitializer中的onStartup导致ContextLoaderListener没有执行。

附公司大佬的解释:

  1. ContextLoader是servlet2.5那个时代的产物,它需要靠web.xml里去拉起servletcontext在启动的时候去初始化RootWebApplicationContext(就是对上面的一个总结);
  2. 在servlet3.0后被SpringBoot自己给干掉了;

惭愧惭愧,本人入行这么些时间,都没有玩过有web.xml的项目,算是入行比较晚。

三、解决

  1. 最基本最官方的一个解决方案把,写一个类去实现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;
        }
    }
    
  2. 现在很多市场上的工具类也都有这个功能,类似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