qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請?jiān)L問 http://qaseven.github.io/

          Spring MVC攔截器實(shí)現(xiàn)分析

          Spring MVC攔截器實(shí)現(xiàn)分析

           一、Servlet Filter與Spring interceptor的執(zhí)行順序

            Filter有順序嗎?我們怎么控制filter的執(zhí)行順序。通過Tomcat的代碼分析,servlet在Filter執(zhí)行完成后才調(diào)用,如有多個(gè)filter怎么控制執(zhí)行順序,首先會(huì)想到在web.xml配置某個(gè)參數(shù),例如order之類的,但查找一下一番,servlet并沒有這個(gè)參數(shù)。試試filter Mapping的配置的先后順序,果然有效,原來filter的執(zhí)行順序就考filter mapping在web.xml中的順序。

            spring interceptor也是這樣的執(zhí)行順序,不過interceptor多一個(gè)配置參數(shù)order通過他也可以來實(shí)現(xiàn)interceptor的執(zhí)行順序。很多應(yīng)用場景中,執(zhí)行順序還是重要的,比如cache和transaction interceptor的執(zhí)行順序,很顯然cache應(yīng)該在transaction之前,這樣發(fā)現(xiàn)命中了就不用打開事務(wù),如果transaction在前,每次都打開事務(wù)即使cache命中,這是一個(gè)無謂東動(dòng)作。

            二、利用springMVC的interceptor實(shí)現(xiàn)頁面性能監(jiān)控(Filter亦可)

            調(diào)優(yōu)第一步,找出耗時(shí)比較長的頁面進(jìn)行優(yōu)化。利用interceptor能輕易搞定。interceptor提供了preHandle和postHandle以及afterCompletion三個(gè)方法。preHandle調(diào)用controller具體方法之前調(diào)用,postHandle完成具體方法之后調(diào)用,afterCompletion完成對(duì)頁面的render以后調(diào)用,至此整個(gè)頁面渲染完成。也就是說我們在preHandle記錄開始的時(shí)間,在afterCompletion記錄結(jié)束的時(shí)間,就可或者整個(gè)頁面生成的時(shí)間。Spring自帶StopWatch工具類來實(shí)現(xiàn)時(shí)間跟蹤,關(guān)鍵一點(diǎn)interceptor不是線程安全的。我們需要借助threadlocal來實(shí)現(xiàn)線程安全。

        1. @Override 
        2.     public boolean preHandle(HttpServletRequest request, 
        3.             HttpServletResponse response, Object handler) throws Exception { 
        4.         if(usePerformance){ 
        5.             StopWatch stopWatch = new StopWatch(handler.toString()); 
        6.             stopWatchLocal.set(stopWatch); 
        7.             stopWatch.start(handler.toString()); 
        8.         } 
        9.          
        10.         return true
        11.     } 
        12.  @Override 
        13.     public void afterCompletion(HttpServletRequest request, 
        14.             HttpServletResponse response, Object handler, Exception ex) 
        15.             throws Exception { 
        16.         if(usePerformance){ 
        17.             StopWatch stopWatch = stopWatchLocal.get(); 
        18.             stopWatch.stop(); 
        19.             String currentPath = request.getRequestURI(); 
        20.             String queryString  = request.getQueryString(); 
        21.             queryString = queryString == null ? "":"?" + queryString; 
        22.             log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis()); 
        23.             stopWatchLocal.set(null); 
        24.         } 
        25.     }
        26.   如果你沒有使用springMVC可以使用filter來完成:

        27. stopWatch.start(); 
        28. doFilterChain(); 
        29. stopWatch.stop();
        30.   三、SpringMVC 攔截器實(shí)現(xiàn)分析

            SpringMVC的攔截器不同于Spring的攔截器,SpringMVC具有統(tǒng)一的入口DispatcherServlet,所有的請求都通過DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也沒有代理,同時(shí)SpringMVC管理的Controller也不有代理。哪不難想到我們在執(zhí)行controller之前做某些動(dòng)作,執(zhí)行完畢做某些動(dòng)作,render完成做某些動(dòng)作。SpringMVC的攔截器對(duì)應(yīng)提供了三個(gè)preHandle,postHandle,afterCompletion方法。只需在三個(gè)方法內(nèi)寫我們需要的邏輯就行,多了都是廢話,還是代碼實(shí)在。

        31. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); 
        32.                 if (interceptors != null) { 
        33.                     for (int i = 0; i < interceptors.length; i++) { 
        34.                         HandlerInterceptor interceptor = interceptors[i]; 
        35. //ha.handle是調(diào)用具體的controller在此之前執(zhí)行preHandle                      if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { 
        36.                             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); 
        37.                             return
        38.                         } 
        39.                         interceptorIndex = i; 
        40.                     } 
        41.                 } 
        42.                 // Actually invoke the handler. 
        43.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        44.   完成調(diào)用之后,調(diào)用render(),最后執(zhí)行afterCompletion()。

        45. if (interceptors != null) { 
        46.                 for (int i = interceptors.length - 1; i >= 0; i--) { 
        47.                     HandlerInterceptor interceptor = interceptors[i]; 
        48.                     interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); 
        49.                 } 
        50.             } 
        51.         } 
        52.         catch (ModelAndViewDefiningException ex) { 
        53.             logger.debug("ModelAndViewDefiningException encountered", ex); 
        54.             mv = ex.getModelAndView(); 
        55.         } 
        56.         catch (Exception ex) { 
        57.             Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); 
        58.             mv = processHandlerException(processedRequest, response, handler, ex); 
        59.             errorView = (mv != null); 
        60.         } 
        61.         // Did the handler return a view to render? 
        62.         if (mv != null && !mv.wasCleared()) { 
        63.             render(mv, processedRequest, response); 
        64.             if (errorView) { 
        65.                 WebUtils.clearErrorRequestAttributes(request); 
        66.             } 
        67.         } 
        68.         else { 
        69.             if (logger.isDebugEnabled()) { 
        70.                 logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + 
        71.                         "': assuming HandlerAdapter completed request handling"); 
        72.             } 
        73.         } 
        74.         // Trigger after-completion for successful outcome. 
        75.         triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
        76. posted on 2011-11-23 16:58 順其自然EVO 閱讀(8207) 評(píng)論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2011年11月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 淅川县| 双江| 丽水市| 南召县| 建瓯市| 西吉县| 绵阳市| 余干县| 澎湖县| 浙江省| 蓝山县| 临高县| 黄龙县| 关岭| 乌兰察布市| 汉川市| 乳山市| 青州市| 岳池县| 翁源县| 建德市| 体育| 南皮县| 离岛区| 孟州市| 南京市| 台中市| 高要市| 河北区| 兰考县| 喀喇| 青阳县| 资阳市| 基隆市| 合肥市| 通许县| 耒阳市| 乐至县| 潞西市| 岳普湖县| 涿州市|