兄弟倆暢遊Tomcat城市的SpringMVC科技園區

一、Tomcat城市

Tomcat這座城市的歷史至關悠久了,經歷過幾回大的變遷後,呈現出很是明顯的地域特徵。golang

從城市往西走,過了城鄉結合部之後,能夠說是滿目瘡痍、一片破敗,這就是Servlet地區,這座城市一開始就是從這個地方發展起來的。web

哎,這都是不少年前的老黃曆了,只有一些老人才知道這些,如今的年輕人都不到這個地方來了,因而就荒蕪了,快成無人區了。編程

城市的中央是Struts地區,人們習慣稱它爲老城區。矮矮的居民樓,窄窄的街道,成羣結隊的老舊工廠。json

雖然如今沒落了,可是置身其中,你依然可以感覺到它曾經輝煌過的痕跡,那時也應該是燈紅酒綠、人聲鼎沸、好不熱鬧。tomcat

如今這裏只剩下一些老年人了,年輕人以爲這裏太陳舊了,都紛紛搬走了,偶爾能見到幾個,那是回來看望父母的。app

從城市往東走,出了老城進入新區,高樓大廈、玻璃幕牆,大寬馬路、人流成河。紅燈綠燈、南來北往,車聲人聲、聲聲不息。函數

這裏充滿了大量的年輕人,節奏感、時尚感、科技感,有夢想、有壓力、有但願。沒錯,這就是大名鼎鼎、聞名遐邇的SpringMVC地區。佈局

技術的發展就像城市的變遷,有新區就有老城。所謂長江後浪推前浪,一浪更比一浪浪,真是夠浪,嗯,golang。spa

編程新說注:設計

第一代web應用Jsp+Servlet,如今基本沒人用了,成了無人區了。

第二代web應用Struts1.x、Struts2,曾經輝煌時不少人用,如今都是進入維護期的老項目了,就像老城區。

第三代web應用SpringMVC,如今如日中天,依然是主戰場,就如同城市的新區。

不過SpringMVC並不是固若金湯,它的挑戰者已經出現,就是響應式web應用,它如今不只要面臨外患,還有來自內憂的困擾。

二、破舊的火車站

request奉主人之命,坐了「一晚上」的火車,「長途跋涉」後來到了tomcat城市,按照約定,他的弟弟response會來這裏接他。request剛下了車,他弟弟就迎了上來,沒想到他跑到站臺上來接本身了。

request邊走邊四處打量着,這座車站雖然略顯破舊,但結構設計合理,層層疊疊、環環相扣,真是建築之美啊。

他忽然意識到本身是第一次來這裏,還不知道路怎麼走,看到不遠處有一老者在掃地,打算前去問路。眼看就要到了,不料被四我的「截胡」了。

其中兩我的說他們要找一個叫MyServlet的人,老者說出門往西走就好了。另外兩我的說要找一個叫FilterDispatcher的人,老者說出門往前走就好了。

看着他們四人離去的背影,老者無奈地搖了搖頭,又自顧自地開始掃地。request上去詢問爲什麼這般,老者解釋道,這四位但是稀客啊,如今像他們這樣的人已經不多了。幾乎都是去找DispatcherServlet的人。

request說道,咱們就是要去找DispatcherServlet呀,老者說,出門跟着人流走,保證能找到。爲了禮貌,request詢問了老者的姓名,老者說,他是Wrapper,在這裏工做十幾年了。

request和response跟老者道謝後,就離開了。出門後,好不容易擠上了一輛公交,一路向東奔去。

編程新說注:

MyServlet通常是一個剛畢業的學生起的名字。

FilterDispatcher是Struts2的核心控制器。

DispatcherServlet是SpringMVC的核心控制器。

Wrapper是Tomcat內部的一種容器組件,負責Servlet的調用執行。

三、SpringMVC科技園區

「前方到站SpringMVC科技園,有下車的乘客,請攜帶好隨身物品,從後門下車」,兩兄弟好不容易擠到後門,下車了。

眼前的這個科技園四四方方,裏面的高大建築佈局合理。門前的寬大道路乾淨筆直,向南北無限延伸。旁邊的小路綠樹成蔭、鮮花滿地。

這裏的一切都極具現代化都市氣息,兄弟倆早已忘我。一陣急促的嘈雜聲響起,哦,原來是綠燈亮了,能夠過馬路了,隨機又淹沒在人羣中。

兩兄弟在園區門口被保安攔下,「恁倆是弄啥嘞?」,保安問道。兩兄弟一聽,咦,河南人,內心樂了。說道,「老鄉,俺是來找一個叫DispatcherServlet的人」。保安道,「那中,他通常均可忙啦,恁倆先去那邊樹蔭下涼快涼快吧」。

一下子功夫,有一箇中年微胖男人來到了門口,就是他了。兩兄弟代表來意後,request遞上了一張「介紹信」,上面彷佛寫着:

圖片描述

DispatcherServlet看後,內心暗罵一句,這是哪一個小兔崽子在寫着玩呢。不過人既然已經來了,那就按照程序走吧。

他就帶着兩兄弟來到了一個房間門口,說先進去檢查一下,看看有沒有「攜帶大件行李物品」。只見response準備進去,一把被他拉回來,說你不用去,只要你哥哥去就好了。

request來到門前,只見上面寫着checkMultipart,推門而入,有個叫MultipartResolver的工做人員,正準備對他搜查,一看Content-Type,嘟囔着說原來只是普通表單提交沒有附件,隨即放棄了對request的檢查,讓他直接出去了。

request一臉懵逼,他原覺得來到這裏後,會有人專門帶着他參觀,給他講解,端茶倒水啥的。誰知就像進了醫院體檢同樣,拿個「單子」亂跑。

正在鬱悶着的request在走過一個叫getHandler的房間門口時,被叫停了,他知道又該進去被檢查了。一個叫RequestMappingHandlerMapping的傢伙坐在電腦後面,request趕忙遞上本身的單子。

那個傢伙瞄了一眼單子後,在輸入框裏敲上「POST /users」關鍵字,點擊搜索按鈕,只見結果的第一條就是一個叫UserController的小夥子。並把這個小夥子的信息打印到一張紙上給了request。

request接過紙,邊往外走邊看,只見上面寫着:

圖片描述

request又是一臉懵逼,這都什麼玩意兒呀。不過定睛一看,發現了熟悉的字眼兒。如UserController、registerUser、User。

request隱隱約約當中記得本身的主人寫過一些和他們相關的東西,好像是這樣的:

圖片描述

此時,request彷彿明白了,剛纔那個傢伙根據個人「單子」,使用電腦搜索,爲我開了個「方子」。說UserController這個小夥子的registerUser方法「能夠治個人病」,其中User是方法入參。

request正準備沾沾自喜,怎麼腦門忽然一陣疼痛,莫非是忘乎所以受了詛咒,哦,不是,是撞到門上了。揉了揉腦殼,便出了門。

三人一行繼續往前走,request內心明白,如今這充其量叫做「作檢查」,後面非給我來一個「大的修裏」不可。又在一個叫作getHandlerAdapter的房間門口停住了。

不過此次兩兄弟都在外面等着,是DispatcherServlet親自拿着給request開的「方子」進去了。不一會他就出來了,又帶出來一位叫RequestMappingHandlerAdapter的人,說這位是高級技工,由他來完成一部分核心工做。

這位高級技工帶着兩兄弟向本身的地盤走去,來到了一個寫着handle的門前,推開門一塊兒進入。這是一個很是大的房間,裏面有好多的工做人員和機器設備,兩兄弟明白,是時候了,重大的事情將在這裏發生。

高級技工讓兩兄弟躺到工做臺上,而後讓全部人員各就各位,接着就是「生死看淡,不服就幹」,因而,一切井井有理地開始了。

一個叫ServletInvocableHandlerMethod的傢伙是本次的主要操盤手,他依次點名了本身的隊友和檢查了要用的設備,一切正常,下面正式開始了。

操盤手拿到給request開的「方子」,發現須要調用registerUser方法,因而先經過反射拿到這個方法的參數,再通過一番解析後變成了MethodParameter類型啦,對,它就表示方法的參數。

操盤手讓他的隊友ParameterNameDiscoverer去查看下參數的名字是什麼,隊友拿到參數,驚奇地發現上面有個@ModelAttribute("user")註解,因而從註解中讀到了user,它就是參數的名字了。

操盤手又讓他的隊友HandlerMethodArgumentResolver去想辦法把參數值搞定,隊友也發現了@ModelAttribute("user")註解,說明這個參數是個模型數據,並且不是簡單類型。因而先打開設備ModelAndViewContainer,發現設備裏並無一個叫user的數據。

隊友明白,須要本身來生成這樣的一個參數了。先拿到參數類型User,而後反射一下構造函數,發現正好有個默認無參的,經過它就new出了一個User類型的對象了。

隊友接着反射一下它的屬性,發現有4個,username、password、email、age。接着從request中恰巧能找出這4個名稱的值,使用WebDataBinderFactory設備把數據類型合理轉化後,設置給了user對象。這樣隊友就把參數值給準備好了。

有了registerUser方法和user參數後,還要知道在哪一個對象上調用才行啊,因而操盤手根據方法所在的類型UserController,去容器中找到它的bean實例,接着就在該實例上經過反射發起了方法調用,傳進去入參,並獲取返回結果。

操盤手拿到返回結果,簡單檢查後發現返回結果不爲null,再檢查request的弟弟response,發現沒有出現錯誤,並且尚未執行結束。因而在ModelAndViewContainer設備上把該請求標記爲還沒有處理完。

而後把返回結果交給隊友HandlerMethodReturnValueHandler去處理,隊友發現方法所在的類UserController上標有@ResponseBody註解(是做爲@RestController的元註解出現的),瞬間就明白方法的返回值是直接做爲web請求的響應的。

因爲方法的返回值是要直接寫入response的,因此就完事了,不用考慮視圖解析這一塊了。所以隊友就在ModelAndViewContainer設備上把本次請求標記爲已處理完成。

接着就把方法的返回值交給本身的好朋友HttpMessageConverter去處理,好朋友看了request的「單子」一眼,發現上面有Accept:application/json,瞬間也明白了,原來他想要的是JSON格式呀。

因而把方法返回值發給合做夥伴Jackson,不一會給他發回告終果,{"code":0,"desc":"success"},好朋友把這個結果甩給了response,叫他拿好了。

好朋友完成了隊友的任務,隊友完成了操盤手的任務,操盤手向高級技工報告,任務已成功完成,請檢閱。

高級技工原本打算輸出一個ModelAndView做爲處理結果呢,一檢查ModelAndViewContainer設備發現請求已被處理完了。罷了,那就返回一個null吧。

門開了,兩兄弟出來了,哥哥request已被「消耗殆盡」,弟弟response「滿載而歸」。DispatcherServlet早已在此等候,他看到高級技工手裏只有一個null,因而記錄了一句話,「No view rendering, null ModelAndView returned.」。

兩兄弟和DispatcherServlet道謝後來到了園區大門口,接着和老鄉保安揮手告別。此時天色已晚,擠上一輛公交車後,直奔火車站而去。

四、就此一別,再無相見

一路搖搖晃晃來到火車站,天已徹底黑透了。返程的列車早已整裝待發,弟弟response拉着哥哥的手準備一塊兒上車,被哥哥拒絕了,哥哥說按照劇情應該只有你一我的回去。個人使命已完成了。

弟弟並不明白哥哥是什麼意思,就問道那咱們還能不能再見面。哥哥笑着說傻孩子,「固然能夠了」。弟弟高興地跳上了車。

伴着一聲長鳴,列車啓動,兄弟倆互相揮手告別,列車漸漸消失在黑夜的黑中。弟弟沒有看到哥哥微笑的眼角流下了流水。

只有哥哥內心明白,他和弟弟,就此一別,再無相見。轉身向車站外走去,看到那個老者依然在自顧自的掃着地。

黑白無常拿着腳鐐手銬,早已在此「恭候多時」,有氣無力的request全然沒法反抗,任由這「二鬼」拖着去「陰曹地府」接受JVM的輪迴。

也許老天不肯意看到一個光榮完成使命的人就這般的「煙消玉損」,就派出了鍾馗來解救他。鍾馗打跑了黑白無常,但願帶request「永生」。

request婉言拒絕,說我非「三界五行」以外,我依然是凡人,依然有本身的宿命。這是任何人都沒法逃離的天然規律。

頃刻,一束白光從天而降,灑滿request的全身,只見request張開雙臂,身輕如燕般的飛向光的源頭,不一會便沒有了蹤影。

來自公衆號:編程新說 李新傑

相關文章
相關標籤/搜索