zoukankan      html  css  js  c++  java
  • spring mvc拦截器原理分析

    我的springMVC+mybatis中的interceptor使用@autowired注入DAO失败,导致报空指针错误,这个是为什么呢?

    :空指针说明没有注入进来,你可以检查一下你的这个拦截器interceptor是不是加了注解@component,并且spring配置文件扫描了这个类,你的类不交给spring容器管理,就不提注入这回事了。

    一、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] view plain copy
     
     print?
    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. @Override   
    14. public void afterCompletion(HttpServletRequest request,   
    15.         HttpServletResponse response, Object handler, Exception ex)   
    16.         throws Exception {   
    17.     if(usePerformance){   
    18.         StopWatch stopWatch = stopWatchLocal.get();   
    19.         stopWatch.stop();   
    20.         String currentPath = request.getRequestURI();   
    21.         String queryString  = request.getQueryString();   
    22.         queryString = queryString == null ? "":"?" + queryString;   
    23.         log.info("access url path:" + currentPath + queryString +  " |time:" + stopWatch.getTotalTimeMillis());   
    24.         stopWatchLocal.set(null);   
    25.     }   
    26. }   
    [java] view plain copy
     
     print?
    1.    

    三、SpringMVC 拦截器实现分析

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

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

    [java] view plain copy
     
     print?
    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] view plain copy
     
     print?
    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] view plain copy
     
     print?
    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);    
  • 相关阅读:
    第37天新版动画系统和有限状态机
    第36天旧版动画系统
    第35天2D游戏相关
    第34天协同程序和异步加载
    第33天力、射线检测、球形检测和延迟函数
    第32天Line渲染器,物理系统和力
    第31天Camera组件和灯光组件
    第29天动态加载、对象池
    第28天3D数学
    第27天3D数学
  • 原文地址:https://www.cnblogs.com/panxuejun/p/7754197.html
Copyright © 2011-2022 走看看