干貨!從上帝視角來看SpringMVC

SpringMVC核心流程圖
干貨!從上帝視角來看SpringMVC
簡單總結

創新互聯建站總部坐落于成都市區,致力網站建設服務有成都網站建設、網站建設、網絡營銷策劃、網頁設計、網站維護、公眾號搭建、微信小程序、軟件開發等為企業提供一整套的信息化建設解決方案。創造真正意義上的網站建設,為互聯網品牌在互動行銷領域創造價值而不懈努力!

首先請求進入DispatcherServlet 由DispatcherServlet 從HandlerMappings中提取對應的Handler

此時只是獲取到了對應的Handle,然后得去尋找對應的適配器,即:HandlerAdapter

拿到對應HandlerAdapter時,這時候開始調用對應的Handler處理業務邏輯了(這時候實際上已經執行完了我們的Controller) 執行完成之后返回一個ModeAndView

這時候交給我們的ViewResolver通過視圖名稱查找出對應的視圖然后返回

最后,渲染視圖 返回渲染后的視圖 -->響應請求

SpringMVC 源碼解析

首先我們查看繼承關系(關鍵查看藍色箭頭路線) 會發現DispatcherServlet無非就是一個HttpServlet
干貨!從上帝視角來看SpringMVC
由此,我們可以去查看Servlet的關鍵方法:service,doGet,doPost

service@Override
br/>@Override
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
proce***equest(request, response);
}
else {
super.service(request, response);}
}
1
2
3
4
5
6
7
8
9
10
11
doGet
@Override
br/>}
}
1
2
3
4
5
6
7
8
9
10
11
doGet
@Override
throws ServletException, IOException {
proce***equest(request, response);}
1
2
3
4
5
doPost
@Override
br/>}
1
2
3
4
5
doPost
@Override
throws ServletException, IOException {
proce***equest(request, response);
}
1
2
3
4
5
這里會發現無論是哪個方法最后都調用了proce***equest(request, response);我們把焦點放在這個方法上,會發現一個核心的方法:doService(request, response);然后會發現這個方法有點不一樣:

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws Exception;

它居然是一個抽象方法…這就得回到剛剛的繼承關系中,找到他的子類了:DispatcherServlet

反正我看到這個方法的實現的時候,腦海里就浮現出4個字:花 里 胡 哨 。代碼太多,就不放在筆記里面了,太占地方了… 為什么這樣說呢? 因為你看完之后會發現關鍵在于:doDispatch(request, response);是的,沒看錯,這一行才是關鍵!

我們把視角切入這個方法 (至于代碼…還是不放進來了… ) 總結一下:

把要用的變量都定義好:比如我們的ModelAndView以及異常…等等;

下面即將看到的是一個熟悉的陌生人(噢不,關鍵詞)

processedRequest = checkMultipart(request);

“Multipart” 這個關鍵詞好像在哪見過??…讓我想想…(漸漸步入了知識盲區) 哦對!在文件上傳的時候!(勉強想起來了。。) 是的,其實這行代碼就是判斷當前請求是否是一個二進制請求(有沒有帶文件) 當然 這里只是提一下,并不是本文的核心內容。。。(有時間的小伙伴可以自己去了解一下)

好的,現在回到我們的主題,來看看這個方法:

mappedHandler = getHandler(processedRequest);

看過我們上面流程圖的同學應該會知道他現在在干嘛。 現在來獲取我們的Handler了…從哪獲取呢? 從他的HandlerMapping里面獲取。

問題1:至于這個HandlerMappings 哪里來的呢

這個等下討論 我們先來看看他獲取的代碼:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我們能看見他是在遍歷一個handlerMappings

問題2:至于這個handlerMapping是什么呢
干貨!從上帝視角來看SpringMVC
是兩個我們不認識的東西,至于是什么,現在說了也不知道,我們繼續往下走,可以看見圖片上1188行代碼, 他從這個mapping 里面獲取了一個handler 如果獲取到了 這個方法就走完了, 不然就下一次循環

問題1解釋:

我們先回到剛剛那個問題,這個HandlerMapping 哪里來的呢。 不多說,上圖:干貨!從上帝視角來看SpringMVC

我們在源碼包的DispatcherServlet.properties文件下會看見, 他定義了圖片里的這些屬性。 重點放在方框內,第一個屬性,就是我們剛看見的HandlerMappings, 也就是說 HandlerMappings也就是他自己事先定義好的呢。至于第二個屬性,咱們待會兒見~

也就是說SpringMVC自己自帶了2個HandlerMapping 來供我們選擇 至于 為什么要有2個呢? 這時候得啟動項目從斷點的角度來看看了;

我們用2種方式來注冊Controller 分別是:

作為Bean的形式:@Component("/test")
br/>@Component("/test")
br/>@Override
System.out.println("1");
return null;}
}
1
2
3
4
5
6
7
8
以Annotation形式:
@Controller
br/>}
}
1
2
3
4
5
6
7
8
以Annotation形式:
@Controller
br/>@RequestMapping("/test2")
System.out.println("test");
return null;
}
}
1
2
3
4
5
6
7
8
我們先用Bean的方式來跑:

視角走到我們的mappedHandler = getHandler(processedRequest);里面
干貨!從上帝視角來看SpringMVC
問題2解釋:

來,跟著箭頭走,我們發現 我們以Bean的形式注冊的Controller 可以從這個BeanNameUrlHandlerMapping里面獲取到對應的Handler ; 這里 我們是不是對于這個HandlerMapping有了懵懂的了解了?

猜想1:

我們來猜一下 如果是以Annotation的形式注冊的Controller的話 就會被第二個HandlerMapping獲取到。 至于對不對 這個問題我們先留著。

我們先讓代碼繼續走,會發現 Handler返回出來緊接著會執行下面這個方法,這個方法我們從流程圖中可以了解到,就是在找一個適配器。

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

問題3:何為適配器?

我們先來看看他這個方法里面干了啥:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
其實能看見他是從一個handlerAdapters屬性里面遍歷了我們的適配器 這個handlerAdapters哪來的呢? 跟我們的HandlerMappings一樣 在他的配置文件里面有寫,就是我們剛剛所說的 待會兒見的那個東西~ 不多說,上圖:
干貨!從上帝視角來看SpringMVC

問題3解釋:

至于什么是適配器,我們結合Handler來講, 就如我們在最開始的總結時所說的, 一開始只是找到了Handler 現在要執行了,但是有個問題,Handler不止一個, 自然而然對應的執行方式就不同了, 這時候適配器的概念就出來了:對應不同的Handler的執行方案。

當找到合適的適配器的時候, 基本上就已經收尾了,因為后面在做了一些判斷之后(判斷請求類型之類的),就開始執行了你的Handler了,上代碼:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

這個mv就是我們的ModlAndView 其實執行完這一行 我們的Controller的邏輯已經執行完了, 剩下的就是尋找視圖 渲染圖的事情了…

我們這里只是使用了Bean的形式執行了一遍流程 假設使用Annotation呢?

SpringMVC BeanName方式和Annotation方式注冊Controller源碼分析

現在我們來使用Annotation來注冊Controller看看。我們這里只看不同的地方。

猜想1證明:

首先在這個HandlerMappings這里之前的那個就不行了 這里采用了另外一個HandlerMapping 其實也就證明了我們的猜想1
干貨!從上帝視角來看SpringMVC
然后就是到了我們的適配器了:

這里我們會看到用的是這個適配器 而我們的Bean方式注冊的Controller 的話 使用的是另外兩個適配器來的,至于有什么區別呢? 我們來看看他執行的時候:

@Override@Nullable
br/>@Nullable
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
1
2
3
4
5
6
我們的Annotation的形式 是拿到這個handler作為一個HandlerMethod 也就是一個方法對象來執行 這時候我們看看Bean是什么樣子的:

@Override@Nullable
br/>@Nullable
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
1
2
3
4
5
6
由最開始可以看到 我們如果以Bean的形式注冊Controller的話 我們的實現一個Controller的接口 在這里 他把我們的handler強制轉換為一個Controller來執行了。

總結

其實我們的SpringMVC關鍵的概念就在于Handler(處理器) 和Adapter(適配器)

通過一個關鍵的HandlerMappings 找到合適處理你的Controller的Handler 然后再通過HandlerAdapters找到一個合適的HandlerAdapter 來執行Handler即Controller里面的邏輯。 最后再返回ModlAndView…

今天就分享到這里了,如果想要繼續了解spring的同學可以關注我的公種號【Java架構君】

本文標題:干貨!從上帝視角來看SpringMVC
文章位置:http://m.kartarina.com/article28/pipjjp.html

成都網站建設公司_創新互聯,為您提供企業建站網站建設品牌網站建設ChatGPT標簽優化網站維護

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

搜索引擎優化
主站蜘蛛池模板: 日韩欧国产精品一区综合无码| 中文字幕乱妇无码AV在线| 无码任你躁久久久久久久| 无码日韩人妻AV一区二区三区| 狠狠躁夜夜躁无码中文字幕| 色窝窝无码一区二区三区色欲| 无码国产激情在线观看| 中文有无人妻vs无码人妻激烈| 亚洲综合无码一区二区痴汉| 东京热人妻无码人av| 无码精品国产va在线观看dvd| 国产色爽免费无码视频| 成人无码Av片在线观看| 亚洲国产成人精品无码区在线网站| 亚洲精品国产日韩无码AV永久免费网 | 人妻无码久久久久久久久久久| 国产精品无码一区二区三区电影| 亚洲av无码专区在线电影天堂| 无码伊人66久久大杳蕉网站谷歌| 无码人妻AⅤ一区二区三区水密桃 无码欧精品亚洲日韩一区夜夜嗨 无码免费又爽又高潮喷水的视频 无码毛片一区二区三区中文字幕 无码毛片一区二区三区视频免费播放 | 无码人妻精品一区二区三区在线| 欲色aV无码一区二区人妻| 无码AV岛国片在线播放| 中文字幕av无码不卡免费| 久久久久亚洲AV无码专区桃色| 毛片一区二区三区无码| 无码熟妇人妻在线视频| 亚洲国产精品无码久久九九大片| 欧洲人妻丰满av无码久久不卡| 无码人妻AV免费一区二区三区| 国产成人午夜无码电影在线观看 | 国产成人无码免费看视频软件| 亚洲中文字幕无码一区 | 无码夫の前で人妻を侵犯| 日韩人妻无码精品久久免费一| 亚洲V无码一区二区三区四区观看 亚洲爆乳精品无码一区二区三区 亚洲爆乳无码一区二区三区 | 久久久久亚洲Av片无码v| 中文字幕无码久久久| 亚洲精品无码鲁网中文电影| 中文字幕人妻无码一区二区三区| 亚洲啪啪AV无码片|