Spring之ContextLoaderListener的作用
Posted juncaoit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之ContextLoaderListener的作用相关的知识,希望对你有一定的参考价值。
在读公司的源码的时候,遇见这个问题,就了解一番。
用法如下:
1 public class PlatformContextLoaderListener extends ContextLoaderListener { 2 3 @Override 4 public void contextInitialized(ServletContextEvent event) { 5 PlatApplicationContext.initProjectConfig(); 6 super.contextInitialized(event); 7 } 8 }
一:介绍
1.说明
Spring org.springframework.web.context.ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
作用:在启动Web容器时,自动装配Spring applicationContext.xml的配置信息。
因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
2.关于ServletContextListener
上文说过,在容器启动的时候,会默认执行她实现的方法。
在我们公司的程序中,先写了我们自己需要走的程序,然后再写了super.contextInitialized(ServletContextEvent sce)方法。
1 /* 2 * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2004 The Apache Software Foundation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package javax.servlet; 19 20 import java.util.EventListener; 21 22 /** 23 * Interface for receiving notification events about ServletContext 24 * lifecycle changes. 25 * 26 * <p>In order to receive these notification events, the implementation 27 * class must be either declared in the deployment descriptor of the web 28 * application, annotated with {@link javax.servlet.annotation.WebListener}, 29 * or registered via one of the addListener methods defined on 30 * {@link ServletContext}. 31 * 32 * <p>Implementations of this interface are invoked at their 33 * {@link #contextInitialized} method in the order in which they have been 34 * declared, and at their {@link #contextDestroyed} method in reverse 35 * order. 36 * 37 * @see ServletContextEvent 38 * 39 * @since Servlet 2.3 40 */ 41 public interface ServletContextListener extends EventListener { 42 43 /** 44 * Receives notification that the web application initialization 45 * process is starting. 46 * 47 * <p>All ServletContextListeners are notified of context 48 * initialization before any filters or servlets in the web 49 * application are initialized. 50 * 51 * @param sce the ServletContextEvent containing the ServletContext 52 * that is being initialized 53 * 54 * @implSpec 55 * The default implementation takes no action. 56 */ 57 default public void contextInitialized(ServletContextEvent sce) {} 58 59 /** 60 * Receives notification that the ServletContext is about to be 61 * shut down. 62 * 63 * <p>All servlets and filters will have been destroyed before any 64 * ServletContextListeners are notified of context 65 * destruction. 66 * 67 * @param sce the ServletContextEvent containing the ServletContext 68 * that is being destroyed 69 * 70 * @implSpec 71 * The default implementation takes no action. 72 */ 73 default public void contextDestroyed(ServletContextEvent sce) {} 74 }
3.再看看ContextLoader
关注API,下面的三个阶段还是有点难理解,程序太多,在第二部分再描述。
第一段说明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。如果查看ContextLoaderServlet的API,可以看到它也关联了ContextLoader这个类而且它继承了HttpServlet类
第二段,ContextLoader创建的是 XmlWebApplicationContext这样一个类,它实现的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext->BeanFactory这样一来spring中的所有bean都由这个类来创建
第三段,讲如何部署applicationContext的xml文件,如果在web.xml中不写任何参数配置信息,默认的路径是"/WEB-INF/applicationContext.xml,在WEB-INF目录下创建的xml文件的名称必须是applicationContext.xml。如果是要自定义文件名可以在web.xml里加入contextConfigLocation这个context参数:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/classes/applicationContext-*.xml
</param-value>
</context-param>
在<param-value> </param-value>里指定相应的xml文件名,如果有多个xml文件,可以写在一起并一“,”号分隔。上面的applicationContext-*.xml采用通配符,比如这那个目录下有applicationContext-ibatis-base.xml,applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都会一同被载入。
4.多配置文件的情况
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
如果applicationContext.xml文件没有在/WEB-INF/下,或文件名不一致,或存在多个Spring配置文件,在web.xml文件中根据下面代码修改
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml,/WEB-INF/applicationContext.xml,/WEB-INF/classes/applicationContext-*.xml
</param-value>
</context-param>
二:ContextLoaderListener加载过程
ContextLoaderListener实现了ServletContextListener接口,ServletContextListener是Java EE标准接口之一,类似tomcat,jetty的java容器启动时便会触发该接口的contextInitialized。
1 java容器启动触发ContextLoaderListener的contextInitialized
2 contextInitialized 方法调用ContextLoader的initWebApplicationContext方法。
3 initWebApplicationContext调用createWebApplicationContext方法
4 createWebApplicationContext 调用determineContextClass方法
显然是从defaultStrategies中加载的
1 /** 2 * Return the WebApplicationContext implementation class to use, either the 3 * default XmlWebApplicationContext or a custom context class if specified. 4 * @param servletContext current servlet context 5 * @return the WebApplicationContext implementation class to use 6 * @see #CONTEXT_CLASS_PARAM 7 * @see org.springframework.web.context.support.XmlWebApplicationContext 8 */ 9 protected Class<?> determineContextClass(ServletContext servletContext) { 10 String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); 11 if (contextClassName != null) { 12 try { 13 return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); 14 } 15 catch (ClassNotFoundException ex) { 16 throw new ApplicationContextException( 17 "Failed to load custom context class [" + contextClassName + "]", ex); 18 } 19 } 20 else { 21 contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); 22 try { 23 return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); 24 } 25 catch (ClassNotFoundException ex) { 26 throw new ApplicationContextException( 27 "Failed to load default context class [" + contextClassName + "]", ex); 28 } 29 } 30 }
ContextLoader 类中有段静态代码:
1 private static final Properties defaultStrategies; 2 3 static { 4 // Load default strategy implementations from properties file. 5 // This is currently strictly internal and not meant to be customized 6 // by application developers. 7 try { 8 ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); 9 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); 10 } 11 catch (IOException ex) { 12 throw new IllegalStateException("Could not load ‘ContextLoader.properties‘: " + ex.getMessage()); 13 } 14 }
ContextLoader.properties 文件内容如下:
1 org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
至此,determineContextClass方法返回的是XmlWebApplicationContext
6 回到 initWebApplicationContext 方法,调用configureAndRefreshWebApplicationContext方法
7 configureAndRefreshWebApplicationContext 调用了AbstractApplicationContext的refresh方法
8 refresh 方法调用了obtainFreshBeanFactory
9 obtainFreshBeanFactory 调用了AbstractRefreshableApplicationContext类的refreshBeanFactory方法
10 refreshBeanFactory调用了XmlWebApplicationContext的loadBeanDefinitions
11 loadBeanDefinitions中加载了对应的applicationContext.xml
参考文档:
1.https://www.cnblogs.com/hello-yao-ge/p/5891435.html
2.https://blog.csdn.net/MrZhangXL/article/details/78587426
以上是关于Spring之ContextLoaderListener的作用的主要内容,如果未能解决你的问题,请参考以下文章