從源碼的角度來看SpringMVC

SpringMVC核心流程圖

簡單總結

首先請求進入DispatcherServlet 由DispatcherServlet 從HandlerMappings中提取對應的Handler 此時只是獲取到了對應的Handle,而後得去尋找對應的適配器,即:HandlerAdapterweb

拿到對應HandlerAdapter時,這時候開始調用對應的Handler處理業務邏輯了(這時候實際上已經執行完了咱們的Controller) 執行完成以後返回一個ModeAndView 這時候交給咱們的ViewResolver經過視圖名稱查找出對應的視圖而後返回 最後,渲染視圖 返回渲染後的視圖 -->響應請求spring

SpringMVC 源碼解析 首先咱們查看繼承關係(關鍵查看藍色箭頭路線) 會發現DispatcherServlet無非就是一個HttpServlet 由此,咱們能夠去查看Servlet的關鍵方法:service,doGet,doPostbash

1.service:mvc

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
            processRequest(request, response);
        }
        else {
            super.service(request, response);
        }
    }
複製代碼

2.doGet:app

@Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }
複製代碼

3.doPost:ide

@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}
複製代碼

這裏會發現不管是哪一個方法最後都調用了processRequest(request, response);咱們把焦點放在這個方法上,會發現一個核心的方法:doService(request, response);而後會發現這個方法有點不同:源碼分析

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

它竟然是一個抽象方法...這就得回到剛剛的繼承關係中,找到他的子類了:DispatcherServletthis

反正我看到這個方法的實現的時候,腦海裏就浮現出4個字:花 裏 胡 哨 。代碼太多,就不放在筆記裏面了,太佔地方了.. 爲何這樣說呢? 由於你看完以後會發現關鍵在於:doDispatch(request, response);是的,沒看錯,這一行纔是關鍵!spa

咱們把視角切入這個方法 (至於代碼..仍是不放進來了.. ) 總結一下: 把要用的變量都定義好:好比咱們的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;
}
複製代碼

咱們能看見他是在遍歷一個handlerMappings 問題2:至於這個handlerMapping是什麼呢

是兩個咱們不認識的東西,至因而什麼,如今說了也不知道,咱們繼續往下走,能夠看見圖片上1188行代碼, 他從這個mapping 裏面獲取了一個handler 若是獲取到了 這個方法就走完了, 否則就下一次循環

問題1解釋: 咱們先回到剛剛那個問題,這個HandlerMapping 哪裏來的呢。 很少說,上圖:

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

也就是說SpringMVC本身自帶了2個HandlerMapping 來供咱們選擇 至於 爲何要有2個呢? 這時候得啓動項目從斷點的角度來看看了;

咱們用2種方式來註冊Controller 分別是:

1.做爲Bean的形式:

@Component("/test")
public class TesrController  implements org.springframework.web.servlet.mvc.Controller{


    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("1");
        return null;
    }
}
複製代碼

2.以Annotation形式:

@Controller
public class AnnotationController {

    @RequestMapping("/test2")
    public Object test(){

        System.out.println("test");

        return null;
    }
}
複製代碼

咱們先用Bean的方式來跑:  視角走到咱們的mappedHandler = getHandler(processedRequest);裏面

問題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"); }

其實能看見他是從一個handlerAdapters屬性裏面遍歷了咱們的適配器 這個handlerAdapters哪來的呢? 跟咱們的HandlerMappings同樣 在他的配置文件裏面有寫,就是咱們剛剛所說的 待會兒見的那個東西~ 很少說,上圖:

問題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 而後就是到了咱們的適配器了:

這裏咱們會看到用的是這個適配器而咱們的Bean方式註冊的Controller 的話 使用的是另外兩個適配器來的,至於有什麼區別呢? 咱們來看看他執行的時候:

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   return handleInternal(request, response, (HandlerMethod) handler);
}
複製代碼

咱們的Annotation的形式 是拿到這個handler做爲一個HandlerMethod 也就是一個方法對象來執行 這時候咱們看看Bean是什麼樣子的:

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   return ((Controller) handler).handleRequest(request, response);
}
複製代碼

由最開始能夠看到咱們若是以Bean的形式註冊Controller的話 咱們的實現一個Controller的接口 在這裏 他把咱們的handler強制轉換爲一個Controller來執行了。

總結 其實咱們的SpringMVC關鍵的概念就在於Handler(處理器) 和Adapter(適配器) 經過一個關鍵的HandlerMappings 找到合適處理你的Controller的Handler 而後再經過HandlerAdapters找到一個合適的HandlerAdapter 來執行Handler即Controller裏面的邏輯。 最後再返回ModlAndView...

相關文章
相關標籤/搜索