SpringMVC的拦截器

一、拦截器 Interceptor 简介

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

在这里插入图片描述

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

在这里插入图片描述

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

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接口:

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

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

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

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

在这里插入图片描述

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

在这里插入图片描述

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

<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 定义如下:

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

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

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方法源码:

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方法源码:

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方法源码:

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);
		}
	}
}

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值