本文結(jié)合上一篇編譯spring的源碼和單元測試以及spring官方文檔,從細(xì)節(jié)入手,學(xué)習(xí)spring frmaework的使用方法以及實(shí)現(xiàn)原理,另一個(gè)目的:學(xué)會(huì)如何查看開源項(xiàng)目源碼
首先從spring入口開始,spring編譯好的源碼中找到/spring-webmvc/src/test/resources/org/springframework/web/context/WEB-INF/web.xml文件,為什么先找這個(gè)文件?(Web.xml詳解 ),
<!-- This servlet must be loaded first to configure the log4j system and create the WebApplicationContext -->
<servlet>
<servlet-name>config</servlet-name>
<servlet-class>org.springframework.framework.web.context.ContextLoaderServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.framework.web.context.XMLWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>log4jPropertiesUrl</param-name>
<param-value>/WEB-INF/log4j_PRODUCTION.properties</param-value>
</init-param>
<!-- This is essential -->
<load-on-startup>1</load-on-startup>
</servlet>
可以看到首先加載org.springframework.framework.web.context.ContextLoaderServlet文件,再eclipse 中Ctrl+Shift+R,搜索此文件,竟然沒找到??,出師不利呀.
百度“找不到ContextLoaderServlet”,提示因在Spring3.0中去掉了
ContextLoaderServlet和Log4jConfigServlet,所以會(huì)出現(xiàn)找不到類的異常錯(cuò)誤。Spring3.0下可以采用另外兩種啟動(dòng)方式:ContextLoaderListener和ContextLoaderPlugIn。建議使用ContextLoaderListener。于是查找ContextLoaderListener文件,這個(gè)總算是有,不明白為什么源碼和配置文件不匹配呢?然后網(wǎng)上找了一個(gè)使用ContextLoaderListener的配置web.xml 。
<!-- 項(xiàng)目中使用Spring 時(shí),applicationContext.xml配置文件中并沒有BeanFactory,要想在業(yè)務(wù)層中的class 文件中直接引用Spring容器管理的bean可通過以下方式-->
<!--1、在web.xml配置監(jiān)聽器ContextLoaderListener-->
<!--ContextLoaderListener的作用就是啟動(dòng)Web容器時(shí),自動(dòng)裝配ApplicationContext的配置信息。因?yàn)樗鼘?shí)現(xiàn)了ServletContextListener這個(gè)接口,在web.xml配置這個(gè)監(jiān)聽器,啟動(dòng)容器時(shí),就會(huì)默認(rèn)執(zhí)行它實(shí)現(xiàn)的方法。
在ContextLoaderListener中關(guān)聯(lián)了ContextLoader這個(gè)類,所以整個(gè)加載配置過程由ContextLoader來完成。
它的API說明
第一段說明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。
如果查看ContextLoaderServlet的API,可以看到它也關(guān)聯(lián)了ContextLoader這個(gè)類而且它實(shí)現(xiàn)了HttpServlet這個(gè)接口
第二段,ContextLoader創(chuàng)建的是 XmlWebApplicationContext這樣一個(gè)類,它實(shí)現(xiàn)的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext->
BeanFactory這樣一來spring中的所有bean都由這個(gè)類來創(chuàng)建
IUploaddatafileManager uploadmanager = (IUploaddatafileManager) ContextLoaderListener.getCurrentWebApplicationContext().getBean("uploadManager");
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--2、部署applicationContext的xml文件-->
<!--如果在web.xml中不寫任何參數(shù)配置信息,默認(rèn)的路徑是"/WEB-INF/applicationContext.xml,
在WEB-INF目錄下創(chuàng)建的xml文件的名稱必須是applicationContext.xml。
如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個(gè)context參數(shù):
在<param-value> </param-value>里指定相應(yīng)的xml文件名,如果有多個(gè)xml文件,可以寫在一起并以“,”號(hào)分隔。
也可以這樣applicationContext-*.xml采用通配符,比如這那個(gè)目錄下有applicationContext-ibatis-base.xml,
applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都會(huì)一同被載入。
在ContextLoaderListener中關(guān)聯(lián)了ContextLoader這個(gè)類,所以整個(gè)加載配置過程由ContextLoader來完成。-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
1.如果在web.xml中不寫任何參數(shù)配置信息,默認(rèn)的路徑是"/WEB-INF/applicationContext.xml, 在WEB-INF目錄下創(chuàng)建的xml文件的名稱必須是applicationContext.xml
2.如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個(gè)context參數(shù)
帶著問題看源碼,1. 默認(rèn)路徑如何指定?2. 自定義文件名如何實(shí)現(xiàn)的?
打開ContextLoaderListener.java 文件。
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}```
進(jìn)入`initWebApplicationContext `方法

此方法中設(shè)置自定義配置文件,如果沒指定,通過refresh()方法調(diào)用默認(rèn)路徑
1. 默認(rèn)路徑如何指定?

未指定contextClassName時(shí),從defaultStrategies取默認(rèn)className


wac 返回默認(rèn)的XmlWebApplicationContext實(shí)例。

查找`XmlWebApplicationContext`的`refresh()`方法,該類中未找到,一直往上層父類中尋找,最終`AbstractApplicationContext`中找到。

`refresh()` 一級(jí)級(jí)調(diào)用直到`XmlWebApplicationContext`的`getDefaultConfigLoactions()`方法

返回默認(rèn)的配置文件地址
2. 自定義文件名如何實(shí)現(xiàn)的?
`public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";`

檢查contextConfigLocation參數(shù)是否指定?如果有,wac.setConfigLocation()添加自定義配置文件。

如果已經(jīng)指定自定義文件了,就不再使用默認(rèn)位置。之前跟到這個(gè)地方發(fā)現(xiàn)`getDefaultConfigLocation()` 返回`null`,并未返回defaultContextLoaction。后來想明白是因?yàn)閣ac 是`XmlWebApplicationContext`實(shí)例,也應(yīng)該調(diào)用`XmlWebApplicationContext`的`getDefaultConfigLocation()`方法,而不是此處父類方法。