• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

SpringMVC拦截器机制和原理

JAVA web前端中文站 3年前 (2017-07-31) 2901次浏览 已收录 1个评论

Struts2 中的拦截器是 filter,而 SpringMVC 中的拦截器是怎样实现的呢?本文将对 SpringMVC 的拦截器机制和原理进行解读。

更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏

Spring Web MVC 的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器)类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

SpringMVC 拦截器常见应用场景

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等。
  • 权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
  • 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如 apache 可以自动记录);
  • 通用行为:读取 cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。
  • OpenSessionInView:如 Hibernate,在进入处理器打开 Session,在完成后关闭 Session。

本质也是 AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

HandlerInterceptor 拦截器接口

 package org.springframework.web.servlet;   public interface HandlerInterceptor {       boolean preHandle(               HttpServletRequest request, HttpServletResponse response,                Object handler)                throws Exception;          void postHandle(               HttpServletRequest request, HttpServletResponse response,                Object handler, ModelAndView modelAndView)                throws Exception;          void afterCompletion(               HttpServletRequest request, HttpServletResponse response,                Object handler, Exception ex)               throws Exception;   }

我们可能注意到拦截器一个有 3 个回调方法,而一般的过滤器 Filter 才两个,这是怎么回事呢?看下面的分析。

  • preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的 Controller 实现);返回值:true 表示继续流程(如调用下一个拦截器或处理器); false 表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过 response 来产生响应;
  • postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过 modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView 也可能为 null。
  • afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于 try-catch-finally 中的 finally,但仅调用处理器执行链中 preHandle 返回 true 的拦截器的 afterCompletion。

SpringMVC 拦截器适配器

有时候我们可能只需要实现三个回调方法中的某一个,如果实现 HandlerInterceptor 接口的话,三个方法必须实现,不管你需不需要,此时 spring 提供了一个 HandlerInterceptorAdapter 适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。

 public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {        //省略代码 此处所以三个回调方法都是空实现,preHandle 返回 true。   }

SpringMVC 拦截器运行机制

SpringMVC 拦截器机制和原理

下面在看一下在拦截过程中被中断的处理。

SpringMVC 拦截器机制和原理

中断流程中,比如是 HandlerInterceptor2 中断的流程(preHandle 返回 false),此处仅调用它之前拦截器的 preHandle 返回 true 的 afterCompletion 方法。

接下来看一下 DispatcherServlet 内部到底是如何工作的吧:

 //doDispatch 方法   //1、处理器拦截器的预处理(正序执行)   HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();   if (interceptors != null) {       for (int i = 0; i < interceptors.length; i++) {       HandlerInterceptor interceptor = interceptors[i];           if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {               //1.1、失败时触发 afterCompletion 的调用               triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);               return;           }           interceptorIndex = i;//1.2、记录当前预处理成功的索引   }   }   //2、处理器适配器调用我们的处理器   mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   //当我们返回 null 或没有返回逻辑视图名时的默认视图名翻译(详解 4.15.5 RequestToViewNameTranslator)   if (mv != null && !mv.hasView()) {       mv.setViewName(getDefaultViewName(request));   }   //3、处理器拦截器的后处理(逆序)   if (interceptors != null) {   for (int i = interceptors.length - 1; i >= 0; i--) {         HandlerInterceptor interceptor = interceptors[i];         interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);   }   }   //4、视图的渲染   if (mv != null && !mv.wasCleared()) {   render(mv, processedRequest, response);       if (errorView) {           WebUtils.clearErrorRequestAttributes(request);   }   //5、触发整个请求处理完毕回调方法 afterCompletion   triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); 

以上是流程的简化代码,中间省略了部分代码,不完整。

 // triggerAfterCompletion 方法   private void triggerAfterCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex,     HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {    // 5、触发整个请求处理完毕回调方法 afterCompletion (逆序从 1.2 中的预处理成功的索引处的拦截器执行)    if (mappedHandler != null) {     HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();     if (interceptors != null) {      for (int i = interceptorIndex; i >= 0; i--) {       HandlerInterceptor interceptor = interceptors[i];       try {        interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);       }       catch (Throwable ex2) {        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);       }      }     }    }   }   

附上本文完整源代码下载链接:http://pan.baidu.com/s/1i5qrVBv 密码:fo9v

【注:本文源自网络文章资源,由站长整理发布】


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:SpringMVC 拦截器机制和原理
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. Four to five servings of this veggie juice have to be consumed per week to find the desired result. However, it is important to find the doctor's opinion first before you take these oral medications since these might have gloomy effects about the body.
    AVichestitte2017-09-04 23:08 回复