web.xml css
<?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 html
這個類繼承了 org.springframework.web.context.ContextLoader java
實現了javax.servlet.ServletContextListener接口 web
在ContextLoader中有一個靜態語句塊 spring
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"; shell
我找了一下這個文件 數據庫
是在ContextLoader.class一個目錄下 apache
來看看這個文件 api
# 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接口的實現類 app
在上面的靜態語句塊的做用是把這個文件讀到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()
開始加載解析和加載相關的文件