前言

SpringMVC 拦截器也是Aop(面向切面)思想构建,但不是 Spring Aop 动态代理实现的,
主要采用责任链和适配器的设计模式来实现,直接嵌入到 SpringMVC 入口代码里面。

流程分析

浏览器请求

DispatcherServlet 执行调用 doService(request, response) 作为 Servlet 主要执行者,
doService(request, response) 通过调用 doDispatch(request, response) 来真正执行请求处理 doDispatch(request, response) 中完成拦截器的添加和拦截器拦截处理
通过 getHandler(HttpServletRequest request) 获取到 HandlerExecutionChain 处理器执行链,
将拦截器注入到 HandlerExecutionChain 的属性中。
分别调用 HandlerExecutionChain 的三个方法,applyPreHandle、applyPostHandle、triggerAfterCompletion,
实现前置拦截/请求提交拦截和请求完成后拦截。
使用责任链的设计模式,实际调用的是HandleInterceptor的三个接口,分别对应preHandle、postHandle、afterCompletion

HandlerExecutionChain 源码分析

public class HandlerExecutionChain {

    private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex; /**
按照列表中interceptor的顺序来执行它们的preHandle方法,直到有一个返回false。
true:表示继续流程(如调用下一个拦截器或处理器)
返回false后:表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,
调用triggerAfterCompletion方法,此时this.interceptorIndex指向上一个返回true的interceptor的位置,
所以它会按逆序执行所有返回true的interceptor的afterCompletion方法。
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
} return true;
} /**
按照逆序执行所有interceptor的postHandle方法
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
} } /**
从最后一次preHandle成功的interceptor处逆序执行afterCompletion方法。
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i]; try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
} }
}

SpringMVC 拦截器原理的更多相关文章

  1. SpringMVC 拦截器实现原理和登录实现

    SpringMVC 拦截器的原理图 springMVC拦截器的实现一般有两种方式 第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口 第二种方 ...

  2. SpringMVC拦截器详解[附带源码分析]

    目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:h ...

  3. SpringMVC拦截器详解

    拦截器是每个Web框架必备的功能,也是个老生常谈的主题了. 本文将分析SpringMVC的拦截器功能是如何设计的,让读者了解该功能设计的原理. 重要接口及类介绍 1. HandlerExecution ...

  4. [转]SpringMVC拦截器详解[附带源码分析]

      目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:ht ...

  5. SpringMVC拦截器详解[附带源码分析](转)

    本文转自http://www.cnblogs.com/fangjian0423/p/springMVC-interceptor.html 感谢作者 目录 前言 重要接口及类介绍 源码分析 拦截器的配置 ...

  6. SpringMVC 07: WEB-INF下的资源访问 + SpringMVC拦截器

    WBE-INF目录下的资源访问 项目配置和Spring博客集(指SpringMVC 02)中配置一样 出于对网站资源的安全性保护,放在WBE-INF目录下的资源不可以被外部直接访问 在WEB-INF/ ...

  7. SpringMVC拦截器的使用

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那 ...

  8. struts2 javaweb 过滤器、监听器 拦截器 原理

    转: 过滤器.监听器 拦截器 过滤器 创建一个 Filter 只需两个步骤: (1)创建 Filter 处理类: (2)在 web.xml 文件中配置 Filter . 创建 Filter 必须实现 ...

  9. Struts2拦截器原理以及实例

    一.Struts2拦截器定义 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现. 2. ...

随机推荐

  1. LSI 9271阵列卡开启JBOD!

    1.开机等待读取到RAID卡后按ctrl+y(进入阵列卡命令符界面) 2.输入AdpSetProp EnableJBOD 1 -a0(开启JBOD功能) AdpSetProp EnableJBOD 0 ...

  2. [python3]未配置locale的主机出现UnicodeDecodeError: 'ascii' codec can't decode byte 0x....的解决

    之前写的发邮件的程序部署到vps的时候出现了 UnicodeDecodeError: 'ascii' codec can't decode byte 0x.... 的错误. 按理说UnicodeDec ...

  3. CSIC_716_20191216【pymysql模块】

    强调:mysql要设置严格模式,在my.ini 配置文件中 sql-mode="strict_trans_tables,only_full_group_by"    ,设置完要重启 ...

  4. Windows 获取windows密码

    #include <iostream> #define Main main #define COLOR_GREEN system("color 2"); #includ ...

  5. webpack 添加eslint代码审查

    1). 添加包 npm install eslint --save-dev npm install eslint-loader --save-dev npm install eslint-plugin ...

  6. JavaScript 原生事件

    1.原生事件的绑定:https://www.cnblogs.com/shsxt/p/7903216.html a.DOM0级事件: 1. 行内事件 2. 元素.on事件名=函数 b.DOM2级事件:a ...

  7. js类数组转数组的方法(ArrayLike)

    1. 什么是类数组ArrayLike(类数组  就是一个普通的  js对象) 类数组对象必须含有 length 属性,且元素属性名必须是数值或者可转换为数值的字符. 类数组对象不是数组对象,所以没有数 ...

  8. spring 对JDBC的支持 (8)

    目录 一.jdbc的简介 二.jdbcTemplate 的使用 2.1 maven 引入spring - jdbc ,c3p0 ,数据库mysql驱动 2.2 配置 数据源以及jdbcTemplate ...

  9. STL unique

    1: template <class ForwardIterator> 2: ForwardIterator unique (ForwardIterator first, ForwardI ...

  10. ICPC Asia Nanning 2017 I. Rake It In (DFS+贪心 或 对抗搜索+Alpha-Beta剪枝)

    题目链接:Rake It In 比赛链接:ICPC Asia Nanning 2017 Description The designers have come up with a new simple ...