Spring MVC拦截器实现分析

简介:

Spring MVC拦截器实现分析

 一、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来实现线程安全。

@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来完成:

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

本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/
目录
相关文章
|
29天前
|
缓存 前端开发 Java
Spring MVC 面试题及答案整理,最新面试题
Spring MVC 面试题及答案整理,最新面试题
85 0
|
29天前
ssm(Spring+Spring mvc+mybatis)——updateDept.jsp
ssm(Spring+Spring mvc+mybatis)——updateDept.jsp
10 0
|
29天前
ssm(Spring+Spring mvc+mybatis)——showDept.jsp
ssm(Spring+Spring mvc+mybatis)——showDept.jsp
9 0
|
28天前
|
SQL JavaScript Java
springboot+springm vc+mybatis实现增删改查案例!
springboot+springm vc+mybatis实现增删改查案例!
23 0
|
28天前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
35 1
|
20天前
|
存储 XML 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南
42 0
|
6天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
20 3
|
6天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
12 1
|
6天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
20 3
|
16天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南