本文結(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()`方法,而不是此處父類方法巾兆。