SpringMVC的拦截器

一、拦截器 Interceptor 简介

SpringMVC的拦截器Interceptor规范,主要是对Controller资源访问时进行拦截操作的技术,当然拦截后可以进行权 限控制,功能增强等都是可以的。拦截器有点类似 Javaweb 开发中的Filter,拦截器与Filter的区别如下图:

由上图,对Filter 和 Interceptor 做个对比:

实现了HandlerInterceptor接口,且被Spring管理的Bean都是拦截器,接口定义如下:

java 复制代码
public interface HandlerInterceptor {

    	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    		return true;
    	}
    	
    	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    	
    	}
    	
    	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    	
    	}
    }

HandlerInterceptor接口方法的作用及其参数、返回值详解如下:

二、拦截器快速入门

编写MyInterceptor01实现HandlerInterceptor接口:

java 复制代码
    public class MyInterceptor01 implements HandlerInterceptor {
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    		System.out.println("Controller方法执行之前...");
    		return true;//放行
    	}
    	
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    		System.out.println("Controller方法执行之后...");
    	}
    	
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    		System.out.println("渲染视图结束,整个流程完毕...");
    	}
    }

配置Interceptor

xml 复制代码
    <!--配置拦截器-->
    <mvc:interceptors>
    	<mvc:interceptor>
    		<!--配置对哪些资源进行拦截操作-->
    		<mvc:mapping path="/**"/>
    		<bean class="com.itheima.interceptor.MyInterceptor01"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

三、拦截器中三个方法的执行顺序

当每个拦截器都是放行状态时,三个方法的执行顺序如下:

当Interceptor1和Interceptor2处于放行,Interceptor3处于不放行时,三个方法的执行顺序如下:

拦截器执行顺序取决于 interceptor 的配置顺序

xml 复制代码
    <mvc:interceptors>
    	<mvc:interceptor>
    		<mvc:mapping path="/target"/>
    		<bean class="com.itheima.interceptor.MyInterceptor02"></bean>
    		</mvc:interceptor>
    	<mvc:interceptor>
    		<mvc:mapping path="/*"/>
    		<bean class="com.itheima.interceptor.MyInterceptor01"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

四、拦截器执行原理

请求到来时会先使用组件HandlerMapping去匹配Controller的方法(Handler)和符合拦截路径的Interceptor,Handler和多个Interceptor被封装成一个HandlerExecutionChain的对象
HandlerExecutionChain 定义如下:

java 复制代码
    public class HandlerExecutionChain {
    	// 映射的Controller的方法
    	private final Object handler;
    	// 当前Handler匹配的拦截器集合
    	private final List<HandlerInterceptor> interceptorList;
    	// ... 省略其他代码 ...
    }

在DispatcherServlet的doDispatch方法中执行拦截器

java 复制代码
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    	// 根据请求信息获得HandlerExecutionChain
    	HandlerExecutionChain mappedHandler = this.getHandler(request);
    	// 获得处理器适配器
    	HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
    	// 执行Interceptor的前置方法,前置方法如果返回false,则该流程结束
    	if (!mappedHandler.applyPreHandle(request, response)) {
    		return;
    	}
    	// 执行handler,一般是HandlerMethod
    	ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    	// 执行后置方法
    	mappedHandler.applyPostHandle(processedRequest, response, mv);
    	// 执行最终方法
    	this.triggerAfterCompletion(processedRequest, response, mappedHandler, e);
    }

跟踪 HandlerExecutionChain的applyPreHandle方法源码:

java 复制代码
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	// 对interceptorList进行遍历,正向遍历,与此同时使用interceptorIndex进行计数
    	for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
    		// 取出每一个Interceptor对象
    		HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
    		// 调用Interceptor的preHandle方法,如果返回false,则直接执行Interceptor的最终方法
    		if (!interceptor.preHandle(request, response, this.handler)) {
    			// 执行Interceptor的最终方法
    			this.triggerAfterCompletion(request, response, (Exception)null);
    			return false;
    		}
    	}
    	return true;
    }

跟踪 HandlerExecutionChain的applyPostHandle方法源码:

java 复制代码
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
    	// 对interceptorList进行遍历,逆向遍历
    	for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
    		// 取出每一个Interceptor
    		HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
    		// 执行Interceptor的postHandle方法
    		interceptor.postHandle(request, response, this.handler, mv);
    	}
    }

跟踪HandlerExecutionChain的triggerAfterCompletion方法源码:

java 复制代码
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // 逆向遍历interceptorList,遍历的个数为执行的applyPreHandle次数-1
    for(int i = this.interceptorIndex; i >= 0; --i) {
    	// 取出每一个Interceptor
    	HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
    		try {
    			// 执行Interceptor的afterCompletion方法
    			interceptor.afterCompletion(request, response, this.handler, ex);
    		} catch (Throwable var7) {
    			logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
    		}
    	}
    }
相关推荐
Bingo_BIG2 天前
Java Spring框架:单表的查询、新增、修改、删除、导入、导出
java·spring·前后端
paopaokaka_luck2 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
牧瀬クリスだ2 天前
YAML配置详解:SpringBoot实战指南
java·spring·yml
需要8262 天前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
paopaokaka_luck2 天前
考研政治刷题小程序(AI推荐题目、ECharts数据分析、章节练习与专项训练、模拟考试、错题本与收藏夹、学习打卡与目标管理、题库和组卷维护)
前端·javascript·spring boot·spring·数据分析·echarts
步行cgn2 天前
Spring 基于 XML 的自动装配:byType 详解
java·后端·spring
边境悍匪2 天前
蜗牛学苑 Java 智能体学习 Day46|贯穿项目 2 思维导图复盘
java·开发语言·vue.js·学习·spring
步行cgn3 天前
Spring c 命名空间注入详解
java·后端·spring
需要8263 天前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat
vx-程序开发3 天前
【计算机毕设】django校园跑腿服务系统83141
java·数据库·vue.js·spring boot·spring·elasticsearch·django