Spring MVC深入源碼之一HttpServletBean

最近想寫一些系列文章來深入探討理解下Spring MVC的運(yùn)行方式及源碼實(shí)現(xiàn)凸丸。好了脱盲,廢話不多說了漂洋,直接進(jìn)入正題。

大家都知道一個(gè)傳統(tǒng)的Web Application都是從web.xml開始的指攒,這個(gè)文件也是Application容器加載項(xiàng)目時(shí)第一個(gè)讀取的。對(duì)于Spring MVC來說僻焚,我們需要在web.xml中配置一個(gè)DispatcherServlet作為前端控制器并為其指定一些初始參數(shù)允悦。從類名就可以看出,DispatcherServlet本質(zhì)上還是一個(gè)Servlet虑啤,只不過多了一些和Spring MVC框架有關(guān)的一些功能隙弛。

今天打算在這里講的并不是DispatcherServlet架馋,而是它父類的父類HttpServletBean,下圖是一個(gè)描述了DispatcherServlet繼承結(jié)構(gòu)的圖全闷,圖中只展示了Spring提供的三個(gè)類绩蜻,其實(shí)在往上就是servlet-api中的HttpServlet, GenericServlet等。

好了室埋,開始上源碼办绝,先從類聲明開始。

public abstract class HttpServletBean extends HttpServlet      
implements EnvironmentCapable, EnvironmentAware {

可以看到HttpServletBean繼承了HttpServlet姚淆,所以它只是在功能上對(duì)HttpServlet進(jìn)行了一些擴(kuò)展孕蝉。并且它實(shí)現(xiàn)了EnvironmentCapable和EnvironmentAware接口。

  • EnviromentCapable接口里定義腌逢,所有實(shí)現(xiàn)它的類必須能返回一個(gè)Environment的實(shí)例降淮。
  • EnvironmentAware接口里定義,所有實(shí)現(xiàn)它的類必須提供一個(gè)setEnvironment的方法以便于set一個(gè)現(xiàn)有的Environment實(shí)例搏讶。

那看到這里佳鳖,相信大家不禁要問,這個(gè)Enviroment又是一個(gè)什么東西媒惕,它起到了什么樣的作用系吩?在這里我不準(zhǔn)備展開說,簡單來說Environmenti 里封裝了3樣?xùn)|西妒蔚,Spring MVC的profile配置信息穿挨,System Properties的一個(gè)Map以及System Environment的一個(gè)Map。

接下去看一下這個(gè)類中的成員變量聲明肴盏,不多就3個(gè)科盛。

protected final Log logger = LogFactory.getLog(getClass());
private final Set<String> requiredProperties = new HashSet<String>();
private ConfigurableEnvironment environment;
  • Log不需要多說了吧,用來記錄日志的菜皂。
  • 一個(gè)名為requiredProperties的HashSet可以用來指定那些你認(rèn)為必須存在的servlet參數(shù)贞绵,可以通過下面這個(gè)方法添加如果有的話。
protected final void addRequiredProperty(String property) {  
     this.requiredProperties.add(property);
}
  • 一個(gè)類型為ConfigurableEnvironment的變量去存放Environment的實(shí)例恍飘。
@Override
public void setEnvironment(Environment environment) {
     this.environment = (ConfigurableEnvironment) environment;
}

然后我們一起來看一下比較關(guān)鍵的一個(gè)方法init,這個(gè)方法覆蓋了它祖先類GenericServlet中定義的空實(shí)現(xiàn)榨崩,并且這個(gè)方法會(huì)在容器初始化每個(gè)Servlet的時(shí)候被調(diào)用一次。


  • 123行實(shí)例化了一個(gè)ServletConfigPropertyValues的對(duì)象常侣,PropertyValues類其實(shí)是一個(gè)容器類蜡饵,它內(nèi)部會(huì)維護(hù)一個(gè)PropertyValue (注意此處沒有s) 的數(shù)組,而PropertyValue是一個(gè)專門存放屬性/參數(shù)的結(jié)構(gòu)胳施,它可以存儲(chǔ)一個(gè)String類型的屬性名以及一個(gè)Object類型的屬性對(duì)象溯祸。
public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable {   
private final String name;   
private final Object value;
....

那么ServletConfigPropertyValues其實(shí)就是一個(gè)存放和Servlet相關(guān)的參數(shù)的容器類,比如那些定義在web.xml中的initParam。

  • 124行使用了一個(gè)PropertyAccessorFactory類里的方法焦辅,并且返回了一個(gè)BeanWrapper, 簡單來說BeanWrapper就是一個(gè)對(duì)象的包裹者博杖,它里面會(huì)存放被包裹對(duì)象的引用并且提供一系列利用了反射機(jī)制的方法去設(shè)置被包裹者的屬性,大家可以看到在這行代碼里傳入了一個(gè)this引用筷登,這里的this指的就是當(dāng)前這個(gè)類的實(shí)例剃根,而實(shí)際中這個(gè)其實(shí)是一個(gè)DispatcherServlet的實(shí)例,因?yàn)槲覀冊(cè)趙eb.xml里使用的是DispatcherServlet而不是直接去使用HttpServletBean前方。

  • 125行new了一個(gè)ServletContextResourceLoader的實(shí)例狈醉,也說一下ResourceLoader吧,這個(gè)接口定義了一些獲取Resource的方法惠险,你可以用它來獲取各種各樣的資源苗傅,比如配置文件,class文件等班巩。那ServletContextResourceLoader的實(shí)現(xiàn)其實(shí)是提供了獲取那些和當(dāng)前Servlet相關(guān)的一些Resource渣慕,它會(huì)通過ServletContext中的一些方法去獲取資源,比如servletContext.getResourceAsStream(), servletContext.getResource()

  • 127行調(diào)用了一個(gè)initBeanWrapper的方法抱慌,這個(gè)方法是一個(gè)空實(shí)現(xiàn)逊桦,可以在子類中擴(kuò)展如果有需要的話锅移。

protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
}
  • 128行調(diào)用了BeanWrapper上的setPropertyValues方法猾浦,并且把前面提到的ServletConfigPropertyValues作為參數(shù)傳了進(jìn)去漆际。這句代碼的作用就是把ServletConfigPropertyValues中的那些Servlet初始化參數(shù)設(shè)置到BeanWrapper所包裹的實(shí)例中的相應(yīng)成員變量里淮菠。(有點(diǎn)拗口。团南。)谈宛。
    舉個(gè)例子,前面已經(jīng)提到BeanWrapper里被包裹對(duì)象其實(shí)是一個(gè)DispatcherServlet户秤,我們平時(shí)在web.xml中定義這個(gè)Servlet的時(shí)候一般都會(huì)有一些initParam, 比如
<init-param>   
    <param-name>contextConfigLocation</param-name>    
    <param-value>classpath*: *-dispatcher-servlet.xml
</param-value></init-param>

那這個(gè)參數(shù)的名字和值就會(huì)作為一個(gè)PropertyVaule存放在ServletConfigPropertyValues中,在128行被調(diào)用的時(shí)候這個(gè)參數(shù)的值就會(huì)被set到被包裹者實(shí)例的相應(yīng)的屬性中, 在這里就是DispatcherServlet的contextConfigLocation中逮矛。

public void setContextConfigLocation(String contextConfigLocation) {   
    this.contextConfigLocation = contextConfigLocation;
}
  • 136行調(diào)用了一個(gè)initServletBean的方法鸡号,這個(gè)方法是一個(gè)抽象方法,真正的實(shí)現(xiàn)是在子類FrameworkServlet里须鼎。

結(jié)語:
從源碼可以看出鲸伴,HttpServletBean是在HttpServlet的基礎(chǔ)上提供了把Servlet配置中相關(guān)的一些屬性,參數(shù)設(shè)置到成員變量上這樣的一個(gè)功能晋控,這么做的好處就是你可以很方便的通過getter/setter方法去獲取參數(shù)值汞窗,而不是通過一個(gè)通用的Map去獲取。

在下一篇將會(huì)深入分析下HttpServletBean的一個(gè)子類FrameworkServlet赡译。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仲吏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裹唆,老刑警劉巖誓斥,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異许帐,居然都是意外死亡劳坑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門成畦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來距芬,“玉大人,你說我怎么就攤上這事循帐∶镅ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵惧浴,是天一觀的道長存和。 經(jīng)常有香客問我,道長衷旅,這世上最難降的妖魔是什么捐腿? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮柿顶,結(jié)果婚禮上茄袖,老公的妹妹穿的比我還像新娘。我一直安慰自己嘁锯,他們只是感情好宪祥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著家乘,像睡著了一般蝗羊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仁锯,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天耀找,我揣著相機(jī)與錄音,去河邊找鬼业崖。 笑死野芒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的双炕。 我是一名探鬼主播狞悲,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼妇斤!你這毒婦竟也來了摇锋?” 一聲冷哼從身側(cè)響起丹拯,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乱投,沒想到半個(gè)月后咽笼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡戚炫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年剑刑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片双肤。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡施掏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出茅糜,到底是詐尸還是另有隱情七芭,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布蔑赘,位于F島的核電站狸驳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缩赛。R本人自食惡果不足惜耙箍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酥馍。 院中可真熱鬧辩昆,春花似錦、人聲如沸旨袒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砚尽。三九已至施无,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尉辑,已是汗流浹背帆精。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隧魄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓隘蝎,卻偏偏與公主長得像购啄,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱么,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在狮含,面了一些公司,掛了不少,但最終還是拿到小米几迄、百度蔚龙、阿里、京東映胁、新浪木羹、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,255評(píng)論 11 349
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,827評(píng)論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.5 Bean scopes When you create...
    SnailTyan閱讀 1,892評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理解孙,服務(wù)發(fā)現(xiàn)坑填,斷路器,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • 引言 一直以來都在使用Spring mvc弛姜,能夠熟練使用它的各種組件脐瑰。但是,它一直像個(gè)黑盒一樣廷臼,我并不知道它內(nèi)部是...
    yoqu閱讀 909評(píng)論 0 24