跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Spring中ContextLoaderListener监听详解

目录前言

一、SpringMVC总览

二、ContextLoaderListener的contextInitialized监听事件

创建Web类型的ApplicationContext执行refresh方法前言web.xml配置文件的部分,方便下面的理解:org.springframework.web.context.ContextLoaderListener

contextConfigLocationclasspath:Resource/SpringConf.xml

springweborg.springframework.web.servlet.DispatcherServletcontextConfigLocation/WEB-INF/springweb.xml1

springweb/

一、SpringMVC总览

SpringMVC启动时会启动WebApplicationContext类型的容器,并且会调用之前分析的refresh方法。

还是从原始的SpringMVC开始,启动方式有三种,配置文件中配置ContextLoadServlet,ContextLoaderListener、ContextLoaderPlugin。

不论哪种方式启动都大致相同。主要包括两部分:

1、ContextLoaderListener监听

初始化Spring容器,WebApplicationContext类型,并且执行refresh方法2、DispatcherServlet(一个特殊的Servlet,如上面的配置web.xml中进行配置了)

1)、DispatcherServlet像普通Servlet一样,init中启动九大件为服务请求做准备HttpServletBean#init=>DispatcherServlet#onRefresh=>DispatcherServlet#initStrategies(初始化九大件) 2)、当上面初始化完成后,则请求进入后拦截转发到DispatcherServlet DispatcherServlet#doService=>DispatcherServlet#doDispatch(执行MVC流程)

二、ContextLoaderListener的contextInitialized监听事件

当Web容器启动时,触发ContextLoaderListener的contextInitialized

方法:

@Override public void contextInitialized(ServletContextEvent event) {initWebApplicationContext(event.getServletContext());}public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {// 省略部分日志和try catch代码long startTime = System.currentTimeMillis();if (this.context == null) {this.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etc if (cwac.getParent() == null) {// The context instance was injected without an explicit parent ->// determine parent for root web application context, if any.

ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, servletContext);}}servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = this.context;} else if (ccl != null) {currentContextPerThread.put(ccl, this.context);}return this.context;}这里需要考虑容器是否其他地方已经创建了,但是不论是否创建。整个Spring MVC启动过程需要经历几个步骤:1、createWebApplicationContext(创建Web类型的ApplicationContext)

2、configureAndRefreshWebApplicationContext(主要是refresh方法执行)

3、将初始化的WebApplicationContext容器,用key为ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE加载到ServletContext容器中创建Web类型的ApplicationContextprotected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("省略");}return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}先判断启动的WebApplicationContext的类型Class,再使用反射初始化。主要是看启动的Class是怎么确定的。

protected Class determineContextClass(ServletContext servletContext) {String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);if (contextClassName != null) {// 省略try catch代码return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());}else {contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());// 省略try catch代码return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());}}先看启动Web时是否有进行配置Class,否则就在默认的配置策略中进行获取。详细可以参见:Spring中的策略模式简单实现与使用分析从配置文件ContextLoader.properties中获取到的类型为(所以如果没有配置默认启动XmlWebApplicationContext,Spring Boot不会启动该类型,但是SpringMVC没有太大差异

):

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext执行refresh方法不管怎么样都回执行configureAndRefreshWebApplicationContext方法,以启动Spring 容器,也就是之前一直分析refresh方法。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac,ServletContext sc) {// 设置ConfigurableWebApplicationContext的容器Id if (ObjectUtils.identityToString(wac).equals(wac.getId())) {// The application context id is still set to its original default value// -> assign a more useful id based on available information String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);if (idParam != null) {wac.setId(idParam);}else {// Generate default id...

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}// 设置Web容器上下文,设置到Spring容器中wac.setServletContext(sc);String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);// 配置location,如果配置的话,则refresh方法时会调用Resource加载,解析,初始化if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}// 设置Environment,refresh时也分析过,如果没有则会从java.lang.System中// 获取数据初始化StandardEnvironment或其子类ConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}// 初始化自定义的容器,如果自己配置的话(我们可以自定义实现ServletContextListener)

customizeContext(sc, wac);// 调用refresh方法wac.refresh();}

1、设置WebApplicationContext的Id

2、设置Web容器上下文,设置到Spring容器中

3、配置location(比如上面配置中的

contextConfigLocation,则refresh方法时会调用Resource加载,解析,初始化)

4、初始化自定义的监听

5、最重要的一步,启动Spring容器(可以从这里开始看:SpringIoc源码(五)- ApplicationContext(一)- 结构梳理)

到此这篇关于Spring中ContextLoaderListener监听详解的文章就介绍到这了,更多相关ContextLoaderListener监听内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:Spring中ApplicationListener的使用解析Spring中的EventListenerMethodProcessor组件详解spring中EventListener的使用方式SpringApplicationRunListener监听器源码详解SpringBoot中的ApplicationListener事件监听器使用详解spring kafka框架中@KafkaListener 注解解读和使用案例

相关文章