web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Archetype Created Web Application</display-name>
<!-- 初始化 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 定义struts2的核心filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<!-- 让struts定义的核心filter拦截所有请求 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- druid数据库监控 -->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<!-- 项目欢迎界面 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<error-code>502</error-code>
<location>/502.html</location>
</error-page>
<error-page>
<error-code>504</error-code>
<location>/504.html</location>
</error-page>
</web-app>
Spring 的入口 org.springframework.web.context.ContextLoaderListener
这个类继承了 org.springframework.web.context.ContextLoader
实现了javax.servlet.ServletContextListener接口
在ContextLoader中有一个静态语句块
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
注意这个private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
我找了一下这个文件
是在ContextLoader.class一个目录下
来看看这个文件
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
注释:默认的WebApplicationContext接口的实现类
在上面的静态语句块的作用是把这个文件读到Properties(defaultStrategies)对象里
ContextLoaderListener实现了ServletContextListener接口
那么启动服务的入口是这个方法contextInitialized
ContextLoader#initWebApplicationContext(ServletContext servletContext)
--》configureAndRefreshWebApplicationContext(cwac, servletContext);
注意看这一行代码String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
这个就是获取web.xml中的内容
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
获取配置文件的内容 找到spring文件的路径
接下来看wac.setConfigLocation(configLocationParam);
我们直接进这2个方法发现了一个严重的问题 2个方法的实现里面都是直接抛出异常的!!!
说明这个是被禁止调用的?
我再看了下ConfigurableWebApplicationContext 这是一个接口
再回来看到了ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; 这个
接着向上找 this.context = createWebApplicationContext(servletContext);
也就是我们找到了创建 wac具体实例的地方
Class<?> contextClass = determineContextClass(sc);protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
最重要的是这一行代码:
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());我们上面提到在静态语句块里面解析了ContextLoader.properties
得到了
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext根据代码我们知道XmlWebApplicationContext就是
wac.setConfigLocation(configLocationParam);中wac的实例
果然我们在它的父类的父类(AbstractRefreshableConfigApplicationContext)中找到了setConfigLocation方法的实现
看里面的实现是把路径解析到configLocations中
AbstractApplicationContext#refresh()
开始加载解析和加载相关的文件
来源:oschina
链接:https://my.oschina.net/u/2347196/blog/516831