测试
先自定义一个拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
注册该拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/*");
}
}
测试,访问接口:
原理
对DispatcherServlet的方法doDispatch打上断点
getHandler不仅找到了当前请求的处理器,并且找到了对应的拦截器。
断点继续往下走,在执行目标方法之前,调用了applyPreHandle
方法,所以猜测这里就会调用拦截器preHandle
方法,并且该方法如果返回false,就会return(被拦截)
进入applyPreHandle
方法,这里先顺序执行所有的拦截器的preHandle
方法,只要有一个返回了false,就会调用triggerAfterCompletion
方法,然后跳出循环
triggerAfterCompletion
方法:注意,这里从当前拦截器开始倒序执行前面以前已经执行过的拦截器的afterCompletion
方法
目标方法执行后,调用了applyPostHandle
方法
applyPostHandle
源代码:这里会倒序执行所有的拦截器的postHandle
方法
继续往下看:
processDispatchResult
方法内部会倒序调用所有拦截器afterCompletion
方法,意味着如果全部流程执行完了,中间没有任何异常,会调用afterCompletion
方法
如果中间过程中出现了异常,会调用triggerAfterCompletion
方法,该方法仍然会倒序执行所有拦截器的afterCompletion
方法。
图示:
总结
1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
2、先来顺序执行 所有拦截器的 preHandle方法
- 1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
- 2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
3、如果任何一个拦截器返回false。直接跳出不执行目标方法
4、所有拦截器都返回True。执行目标方法
5、倒序执行所有拦截器的postHandle方法。
6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
7、页面成功渲染完成以后,也会倒序触发 afterCompletion