Spring MVC拦截器实现分析

开发 后端
SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。

一、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); 
        } 
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

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

stopWatch.start(); 
doFilterChain(); 
stopWatch.stop(); 
  • 1.
  • 2.
  • 3.

三、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()); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

完成调用之后,调用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); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

原文链接:http://exceptioneye.iteye.com/blog/1267248

【编辑推荐】

  1. 用Spring让Java Mail支持简化邮件发送
  2. 对Spring AOP框架实现的结构分析
  3. spring的MVC国际化的设置
  4. 简单介绍Spring中接口注入的三种方式
  5. 详细介绍JSF和MVC
责任编辑:林师授 来源: 温柔的羊的博客
相关推荐

2025-02-28 08:14:53

2009-07-08 17:02:11

JDK实现调用拦截器

2009-06-24 16:00:00

2009-09-27 17:37:32

Hibernate拦截

2025-01-02 10:10:51

2009-06-25 15:59:21

Struts2教程拦截器

2023-03-10 19:36:47

2023-09-05 08:58:07

2011-05-16 10:14:11

Hibernate

2009-02-04 14:45:06

2009-06-04 08:01:25

Struts2拦截器原理

2024-05-06 00:00:00

C#工具代码

2020-03-25 17:55:30

SpringBoot拦截器Java

2009-06-25 15:54:42

Struts2教程拦截器

2012-02-03 13:27:16

2024-02-28 09:35:52

2009-02-04 14:19:38

2013-11-04 09:35:38

Firefox插件拦截FLASH

2022-09-28 12:39:46

axios拦截器

2024-05-13 09:32:06

拦截器HTTP中间件
点赞
收藏

51CTO技术栈公众号