Spring MVC攔截器實現分析

1、Servlet Filter與Spring interceptor的執行順序 java

      Filter有順序嗎?咱們怎麼控制filter的執行順序。經過Tomcat的代碼分析,servlet在Filter執行完成後才調用,若有多個filter怎麼控制執行順序,首先會想到在web.xml配置某個參數,例如order之類的,但查找一下一番,servlet並無這個參數。試試filter Mapping的配置的前後順序,果真有效,原來filter的執行順序就考filter mapping在web.xml中的順序。 web

spring interceptor也是這樣的執行順序,不過interceptor多一個配置參數order經過他也能夠來實現interceptor的執行順序。不少應用場景中,執行順序仍是重要的,好比cache和transaction interceptor的執行順序,很顯然cache應該在transaction以前,這樣發現命中了就不用打開事務,若是transaction在前,每次都打開事務即便cache命中,這是一個無謂東動做。 spring

 

2、利用springMVC的interceptor實現頁面性能監控(Filter亦可) 安全

      調優第一步,找出耗時比較長的頁面進行優化。利用interceptor能輕易搞定。interceptor提供了preHandle和postHandle以及afterCompletion三個方法。preHandle調用controller具體方法以前調用,postHandle完成具體方法以後調用,afterCompletion完成對頁面的render之後調用,至此整個頁面渲染完成。也就是說咱們在preHandle記錄開始的時間,在afterCompletion記錄結束的時間,就可或者整個頁面生成的時間。Spring自帶StopWatch工具類來實現時間跟蹤,關鍵一點interceptor不是線程安全的。咱們須要藉助threadlocal來實現線程安全。 app

@Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        if(usePerformance){
        	StopWatch stopWatch = new StopWatch(handler.toString());
            stopWatchLocal.set(stopWatch);
            stopWatch.start(handler.toString());
        }
        
        return true;
    }
 @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    	if(usePerformance){
    		StopWatch stopWatch = stopWatchLocal.get();
            stopWatch.stop();
            String currentPath = request.getRequestURI();
            String queryString  = request.getQueryString();
            queryString = queryString == null ? "":"?" + queryString;
            log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis());
            stopWatchLocal.set(null);
    	}
        
    }

 若是你沒有使用springMVC可使用filter來完成 ide

stopWatch.start();
doFilterChain();
stopWatch.stop();



3、SpringMVC 攔截器實現分析 工具

SpringMVC的攔截器不一樣於Spring的攔截器,SpringMVC具備統一的入口DispatcherServlet,全部的請求都經過DispatcherServlet,因此只須要在DispatcherServlet上作文章便可,DispatcherServlet也沒有代理,同時SpringMVC管理的Controller也不有代理。哪不難想到咱們在執行controller以前作某些動做,執行完畢作某些動做,render完成作某些動做。SpringMVC的攔截器對應提供了三個preHandle,postHandle,afterCompletion方法。只需在三個方法內寫咱們須要的邏輯就行,多了都是廢話,仍是代碼實在 post

HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
				if (interceptors != null) {
					for (int i = 0; i < interceptors.length; i++) {
						HandlerInterceptor interceptor = interceptors[i];
//ha.handle是調用具體的controller在此以前執行preHandle						if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
							triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
							return;
						}
						interceptorIndex = i;
					}
				}

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



完成調用以後,調用render(),最後執行afterCompletion()
if (interceptors != null) {
					for (int i = interceptors.length - 1; i >= 0; i--) {
						HandlerInterceptor interceptor = interceptors[i];
						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
					}
				}
			}
			catch (ModelAndViewDefiningException ex) {
				logger.debug("ModelAndViewDefiningException encountered", ex);
				mv = ex.getModelAndView();
			}
			catch (Exception ex) {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(processedRequest, response, handler, ex);
				errorView = (mv != null);
			}

			// Did the handler return a view to render?
			if (mv != null && !mv.wasCleared()) {
				render(mv, processedRequest, response);
				if (errorView) {
					WebUtils.clearErrorRequestAttributes(request);
				}
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
							"': assuming HandlerAdapter completed request handling");
				}
			}

			// Trigger after-completion for successful outcome.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
相關文章
相關標籤/搜索