SpingMVC解析

springMVC (2).jpg

這是一個(gè)最經(jīng)典的SpringMVC執(zhí)行流程圖爪模,其中最核心的三個(gè)地方是: HandlerMapping霉猛、HandlerAdapterHttpMessageConverter

首先,從DispatcherServlet入手,先看下DispatcherServlet繼承圖:

DispatcherServlet.png

從圖可以得知,DispatcherServlet本質(zhì)上就是Servlet,那么Servlet生命周期最主要的的三個(gè)方法時(shí):void init(ServletConfig config),void service(ServletRequest request,ServletResponse response)劳景,void destroy()瓮钥。
看了源代碼之后發(fā)現(xiàn)DispatcherServlet里面根本沒有service這個(gè)方法,這個(gè)時(shí)候找到它的父類FrameworkServlet 琼梆,


sercice.png
processRequest.png
doService.png

doDispatch,最主要的方法扣猫,用來分發(fā)請(qǐng)求勺远,核心的邏輯都在這里面(截圖有限,自己看源碼吧)

doDispatcher.png
doDispatcher2.png

主要的:
1.checkMultipart方法檢查是否是二進(jìn)制的請(qǐng)求(文件上傳的請(qǐng)求)

checkMultipart.png

2.mappingHandler=getHandler(request)

doDispatcher (2).png

返回的是HandlerExecutionChain(處理執(zhí)行鏈)

DispatcherServlet (2).png

再看DispatcherServlet.properties其實(shí)就是包裝了不同的Mapping來判斷通過何種方式來配置。

HandlerExecutionChain(處理執(zhí)行鏈)包含兩部分內(nèi)容,一部分是請(qǐng)求對(duì)應(yīng)的控制器,一部分是攔截器,真正執(zhí)行handle之前,有一系列操作,例如數(shù)據(jù)轉(zhuǎn)換,格式化,數(shù)據(jù)驗(yàn)證這些,都是由攔截器來做的

另外需要注意的是,假如你自定義了n個(gè)攔截器,會(huì)發(fā)現(xiàn)HandlerExecutionChain會(huì)有n+1個(gè)攔截器,說明有一個(gè)是他內(nèi)部有的,從這里我們可以知道它的執(zhí)行順序,比如這里要先執(zhí)行攔截器,再執(zhí)行我們控制器,所以這個(gè)東西被稱為處理執(zhí)行鏈

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

![Uploading applyPreHandler_524696.png . . .]

getHandlerAdapter.png

HandlerAdapater(處理器適配器)恬偷,用來執(zhí)行handler(控制器,即contorller)
這里判斷handler適不適合這個(gè)RequestMappingAdapter肆良,適合就返回

if(ha.supports(handler))
         return ha;

獲取方法類型

String method = reqyest,getMethod();
 if(!mappedHandler.applyPreHandle(processedRequest, response)){
            return;
  }
applyPreHandler.png

這里主要遍歷攔截器。

// Actually invoke the handler.
  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

這里去調(diào)用handler方法曲秉,這個(gè)方法會(huì)做很多事情承二,比如參數(shù)自動(dòng)裝入。

然后是

    @RequestMapping(value = "/golist.do")
    public ModelAndView golist(HttpServletRequest request) {
        return new ModelAndView("/views/module/advise/list.jsp");
    }

再繼續(xù)

//默認(rèn)視圖名稱
 applyDefaultViewName(request, mv);

像下面這個(gè) 返回的只有model 沒有 view

@RequestMapping(value = "/saveEntity.do")
    public @ResponseBody AjaxResult saveByEntity(HttpServletRequest request, Advise entity) {
        LoginUser loginUser = LoginUserUtil.getCurrentUser(request);
        adviseService.saveEntity(loginUser, entity);
        return AjaxResult.warpAjaxResult(true);
}

繼續(xù)往下

 mappedHandler.applyPostHandle(processedRequest, response, mv);
 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
        throws Exception
    {
        if(getInterceptors() == null)
            return;
        for(int i = getInterceptors().length - 1; i >= 0; i--)
        {
            HandlerInterceptor interceptor = getInterceptors()[i];
            interceptor.postHandle(request, response, handler, mv);
        }
    }

從這里我們知道,Interceptor的執(zhí)行順序是反過來的:如圖

Interceptor.png

再繼續(xù)

 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception)
        throws Exception
    {
        boolean errorView = false;
        if(exception != null)
            if(exception instanceof ModelAndViewDefiningException)
            {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException)exception).getModelAndView();
            } else
            {
                Object handler = mappedHandler == null ? null : mappedHandler.getHandler();
                mv = processHandlerException(request, response, handler, exception);
                errorView = mv != null;
            }
        if(mv != null && !mv.wasCleared())
        {
            render(mv, request, response);
            if(errorView)
                WebUtils.clearErrorRequestAttributes(request);
        } else
        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Null ModelAndView returned to DispatcherServlet with name '").append(getServletName()).append("': assuming HandlerAdapter completed request handling").toString());
        if(WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted())
            return;
        if(mappedHandler != null)
            mappedHandler.triggerAfterCompletion(request, response, null);
    }
 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
        throws Exception
    {
        Locale locale = localeResolver.resolveLocale(request);
        response.setLocale(locale);
        View view;
        if(mv.isReference())
        {
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if(view == null)
                throw new ServletException((new StringBuilder()).append("Could not resolve view with name '").append(mv.getViewName()).append("' in servlet with name '").append(getServletName()).append("'").toString());
        } else
        {
            view = mv.getView();
            if(view == null)
                throw new ServletException((new StringBuilder()).append("ModelAndView [").append(mv).append("] neither contains a view name nor a ").append("View object in servlet with name '").append(getServletName()).append("'").toString());
        }
        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Rendering view [").append(view).append("] in DispatcherServlet with name '").append(getServletName()).append("'").toString());
        try
        {
            //這里決定究竟是轉(zhuǎn)發(fā)還是重定向,或者說變成其他視圖
            view.render(mv.getModelInternal(), request, response);
        }
        catch(Exception ex)
        {
            if(logger.isDebugEnabled())
                logger.debug((new StringBuilder()).append("Error rendering view [").append(view).append("] in DispatcherServlet with name '").append(getServletName()).append("'").toString(), ex);
            throw ex;
        }
    }
  public void render(Map model, HttpServletRequest request, HttpServletResponse response)
        throws Exception
    {
        if(logger.isTraceEnabled())
            logger.trace((new StringBuilder()).append("Rendering view with name '").append(beanName).append("' with model ").append(model).append(" and static attributes ").append(staticAttributes).toString());
        Map mergedModel = createMergedOutputModel(model, request, response);
        prepareResponse(request, response);
        renderMergedOutputModel(mergedModel, request, response);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市牵舱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慧妄,老刑警劉巖窟蓝,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贮折,警方通過查閱死者的電腦和手機(jī)筐带,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來作儿,“玉大人械姻,你說我怎么就攤上這事材部。” “怎么了棵磷?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵晋涣,是天一觀的道長(zhǎng)仪媒。 經(jīng)常有香客問我,道長(zhǎng)谢鹊,這世上最難降的妖魔是什么算吩? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮佃扼,結(jié)果婚禮上偎巢,老公的妹妹穿的比我還像新娘。我一直安慰自己兼耀,他們只是感情好压昼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘤运,像睡著了一般窍霞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拯坟,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天但金,我揣著相機(jī)與錄音,去河邊找鬼似谁。 笑死傲绣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巩踏。 我是一名探鬼主播秃诵,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼塞琼!你這毒婦竟也來了菠净?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤彪杉,失蹤者是張志新(化名)和其女友劉穎毅往,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體派近,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡攀唯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渴丸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侯嘀。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡另凌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出戒幔,到底是詐尸還是另有隱情吠谢,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布诗茎,位于F島的核電站工坊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敢订。R本人自食惡果不足惜王污,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枢析。 院中可真熱鬧玉掸,春花似錦、人聲如沸醒叁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)把沼。三九已至啊易,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饮睬,已是汗流浹背租谈。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捆愁,地道東北人割去。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像昼丑,于是被迫代替她去往敵國(guó)和親呻逆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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