spring framework 源碼分析,從入口開始

本文結(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中去掉了ContextLoaderServletLog4jConfigServlet,所以會(huì)出現(xiàn)找不到類的異常錯(cuò)誤。Spring3.0下可以采用另外兩種啟動(dòng)方式:ContextLoaderListenerContextLoaderPlugIn。建議使用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 `方法
![initWebApplicationContext
](http://upload-images.jianshu.io/upload_images/2783430-03bac226391c8edd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
此方法中設(shè)置自定義配置文件,如果沒指定,通過refresh()方法調(diào)用默認(rèn)路徑
1. 默認(rèn)路徑如何指定?
![determineContextClass](http://upload-images.jianshu.io/upload_images/2783430-40b26f2ecf3f98fd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
未指定contextClassName時(shí),從defaultStrategies取默認(rèn)className
![defaultStrategies](http://upload-images.jianshu.io/upload_images/2783430-c6a76bdf1aa6ba23.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![ContexLoad.properties](http://upload-images.jianshu.io/upload_images/2783430-5d127fa0716c8980.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
wac 返回默認(rèn)的XmlWebApplicationContext實(shí)例。
![configureAndRefreshWebApplicationContext](http://upload-images.jianshu.io/upload_images/2783430-6f6ea554f3cffd60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
查找`XmlWebApplicationContext`的`refresh()`方法,該類中未找到,一直往上層父類中尋找,最終`AbstractApplicationContext`中找到。
![refresh_getDefaultConfigLocations](http://upload-images.jianshu.io/upload_images/2783430-5121dfe1a51ac594.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
`refresh()` 一級(jí)級(jí)調(diào)用直到`XmlWebApplicationContext`的`getDefaultConfigLoactions()`方法
![getDefaultConfigLocations](http://upload-images.jianshu.io/upload_images/2783430-e02c18babd6f24dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
返回默認(rèn)的配置文件地址
2. 自定義文件名如何實(shí)現(xiàn)的?
`public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";`
![configureAndRefreshWebApplicationContext](http://upload-images.jianshu.io/upload_images/2783430-6f6ea554f3cffd60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
檢查contextConfigLocation參數(shù)是否指定?如果有,wac.setConfigLocation()添加自定義配置文件。
![getConfigLocations](http://upload-images.jianshu.io/upload_images/2783430-2d7f0d8462d02e4f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如果已經(jīng)指定自定義文件了,就不再使用默認(rèn)位置。之前跟到這個(gè)地方發(fā)現(xiàn)`getDefaultConfigLocation()` 返回`null`,并未返回defaultContextLoaction。后來想明白是因?yàn)閣ac 是`XmlWebApplicationContext`實(shí)例,也應(yīng)該調(diào)用`XmlWebApplicationContext`的`getDefaultConfigLocation()`方法,而不是此處父類方法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容