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

     

    Java代码  收藏代码
    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.   
    13.   
    14.  @Override  
    15.     public void afterCompletion(HttpServletRequest request,  
    16.             HttpServletResponse response, Object handler, Exception ex)  
    17.             throws Exception {  
    18.         if(usePerformance){  
    19.             StopWatch stopWatch = stopWatchLocal.get();  
    20.             stopWatch.stop();  
    21.             String currentPath = request.getRequestURI();  
    22.             String queryString  = request.getQueryString();  
    23.             queryString = queryString == null ? "":"?" + queryString;  
    24.             log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis());  
    25.             stopWatchLocal.set(null);  
    26.         }  
    27.           
    28.     }  

     

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

     

    Java代码  收藏代码
    1. stopWatch.start();  
    2. doFilterChain();  
    3. stopWatch.stop();  

     

    三、SpringMVC 拦截器实现分析

     

     

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

     

    Java代码  收藏代码
    1. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();  
    2.                 if (interceptors != null) {  
    3.                     for (int i = 0; i < interceptors.length; i++) {  
    4.                         HandlerInterceptor interceptor = interceptors[i];  
    5. //ha.handle是调用具体的controller在此之前执行preHandle                      if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {  
    6.                             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  
    7.                             return;  
    8.                         }  
    9.                         interceptorIndex = i;  
    10.                     }  
    11.                 }  
    12.   
    13.                 // Actually invoke the handler.  
    14.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

     

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

     

    Java代码  收藏代码
    1. if (interceptors != null) {  
    2.                 for (int i = interceptors.length - 1; i >= 0; i--) {  
    3.                     HandlerInterceptor interceptor = interceptors[i];  
    4.                     interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);  
    5.                 }  
    6.             }  
    7.         }  
    8.         catch (ModelAndViewDefiningException ex) {  
    9.             logger.debug("ModelAndViewDefiningException encountered", ex);  
    10.             mv = ex.getModelAndView();  
    11.         }  
    12.         catch (Exception ex) {  
    13.             Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
    14.             mv = processHandlerException(processedRequest, response, handler, ex);  
    15.             errorView = (mv != null);  
    16.         }  
    17.   
    18.         // Did the handler return a view to render?  
    19.         if (mv != null && !mv.wasCleared()) {  
    20.             render(mv, processedRequest, response);  
    21.             if (errorView) {  
    22.                 WebUtils.clearErrorRequestAttributes(request);  
    23.             }  
    24.         }  
    25.         else {  
    26.             if (logger.isDebugEnabled()) {  
    27.                 logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
    28.                         "': assuming HandlerAdapter completed request handling");  
    29.             }  
    30.         }  
    31.   
    32.         // Trigger after-completion for successful outcome.  
    33.         triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  
  • 相关阅读:
    Oracle 分析函数
    Oracle 增加修改删除字段
    Oracle 重置序列
    End2EndIT
    Hyperledger Fabric SDK use case 1
    云计算中8项核心技术
    Cloud
    JVM Guide
    微信公众平台PHP开发
    在Linux系统环境下修改MySQL的root密码
  • 原文地址:https://www.cnblogs.com/chenying99/p/2500854.html
Copyright © 2020-2023  润新知