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());
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);