SpringMVC拦截器实现分析

  一、Servlet Filter与Spring interceptor的执行顺序

  Filter有顺序吗?我们怎么控制filter的执行顺序。通过Tomcat的代码分析,servlet在Filter执行完成后才调用,如有多个filter怎么控制执行顺序,首先会想到在web.xml配置某个参数,例如order之类的,但查找一下一番,servlet并没有这个参数。试试filter Mapping的配置的先后顺序,果然有效,原来filter的执行顺序就考filter mapping在web.xml中的顺序。

  spring interceptor也是这样的执行顺序,不过interceptor多一个配置参数order通过他也可以来实现interceptor的执行顺序。很多应用场景中,执行顺序还是重要的,比如cache和transaction interceptor的执行顺序,很显然cache应该在transaction之前,这样发现命中了就不用打开事务,如果transaction在前,每次都打开事务即使cache命中,这是一个无谓东动作。

  二、利用springMVC的interceptor实现页面性能监控(Filter亦可)

  调优第一步,找出耗时比较长的页面进行优化。利用interceptor能轻易搞定。interceptor提供了preHandle和postHandle以及afterCompletion三个方法。preHandle调用controller具体方法之前调用,postHandle完成具体方法之后调用,afterCompletion完成对页面的render以后调用,至此整个页面渲染完成。也就是说我们在preHandle记录开始的时间,在afterCompletion记录结束的时间,就可或者整个页面生成的时间。Spring自带StopWatch工具类来实现时间跟踪,关键一点interceptor不是线程安全的。我们需要借助threadlocal来实现线程安全。

  

@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{if(usePerformance){StopWatchstopWatch=newStopWatch(handler.toString());stopWatchLocal.set(stopWatch);stopWatch.start(handler.toString());}returntrue;}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{if(usePerformance){StopWatchstopWatch=stopWatchLocal.get();stopWatch.stop();StringcurrentPath=request.getRequestURI();StringqueryString=request.getQueryString();queryString=queryString==null?””:”?”+queryString;(“accessurlpath:”+currentPath+queryString+”|time:”+stopWatch.getTotalTimeMillis());stopWatchLocal.set(null);}}

  如果你没有使用springMVC可以使用filter来完成:

  

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

  三、SpringMVC 拦截器实现分析

  SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。哪不难想到我们在执行controller之前做某些动作,执行完毕做某些动作,render完成做某些动作。SpringMVC的拦截器对应提供了三个preHandle,postHandle,afterCompletion方法。只需在三个方法内写我们需要的逻辑就行,多了都是废话,还是代码实在。

  

HandlerInterceptor[]interceptors=mappedHandler.getInterceptors();if(interceptors!=null){for(inti=0;i<interceptors.length;i++){HandlerInterceptorinterceptor=interceptors[i];//ha.handle是调用具体的controller在此之前执行preHandleif(!interceptor.preHandle(processedRequest,response,mappedHandler.getHandler())){triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null);return;}interceptorIndex=i;}}//Actuallyinvokethehandler.mv=ha.handle(processedRequest,response,mappedHandler.getHandler());

  完成调用之后,调用render(),最后执行afterCompletion()。

  

if(interceptors!=null){for(inti=interceptors.length-1;i>=0;i–){HandlerInterceptorinterceptor=interceptors[i];interceptor.postHandle(processedRequest,response,mappedHandler.getHandler(),mv);}}}catch(ModelAndViewDefiningExceptionex){logger.debug(“ModelAndViewDefiningExceptionencountered”,ex);mv=ex.getModelAndView();}catch(Exceptionex){Objecthandler=(mappedHandler!=null?mappedHandler.getHandler():null);mv=processHandlerException(processedRequest,response,handler,ex);errorView=(mv!=null);}//Didthehandlerreturnaviewtorender?if(mv!=null&&!mv.wasCleared()){render(mv,processedRequest,response);if(errorView){WebUtils.clearErrorRequestAttributes(request);}}else{if(logger.isDebugEnabled()){logger.debug(“NullModelAndViewreturnedtoDispatcherServletwithname'”+getServletName()+”‘:assumingHandlerAdaptercompletedrequesthandling”);}}//Triggerafter-completionforsuccessfuloutcome.triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null);

只要功夫深,铁棒磨成绣花针。

SpringMVC拦截器实现分析

相关文章:

你感兴趣的文章:

标签云: