注意:所有文章除特别说明外,转载请注明出处.
SpringMVC 解析
1.什么是拦截器:
SpringMVC提供了拦截器机制:
HandlerInterceptor:SpringMVC
允许在目标方法之前进行一些拦截工作,或者在目标方法之后进行一些其他的处理。
perHandle:在目标方法执行之前,返回boolean,return true(放行);return false 不放行;
postHandle:在目标方法执行之后调用,目标方法调用之后;
aftercompletion:在整个请求完成之后,来到目标页面之后;资源响应之后;
2.拦截器怎么使用:
1.实现HandlerInterceptor 接口 实现三个方法!
2.配置这个拦截器需要拦截那些请求
- 拦截器是一个接口!
- 实现HandleInterceptor接口:
- 配置拦截器
3.拦截器的运行流程
3.1.正常运行流程:
拦截器的preHandle———目标方法———拦截器的postHandle———页面———拦截器的afterCompletion
3.2.其他流程:
1. 只要preHandle 不放行,其他流程均完蛋。
2. 放行之后,目标方法炸了,preHandle 放行,postHandle没有执行,**但是afterCompletion执行了。**
3.3.多个拦截器的流程:
正常流程:
异常流程:
1)、First只要不放行,后面全都没有
2)、First 放行,但是Second 不放行。但是First 的afterCompletion还要执行。
总结:==已放行的拦截器的 afterCompletion 都要执行==
==拦截器的 preHandle 是顺序执行的,但是 postHandle 和 afterCompletion 是逆序执行的。==
3.拦截器的源码流程
doDispatch
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
PreHandle
1 | boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
PostHandle
1 | void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) |
processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//页面渲染
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
//页面正常,执行afterCompletion,即使没有走到这里afterCompletion 也会执行
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//逆序执行(通过之前记录的索引),把之前所有放行的拦截器的AfterCompletion全部执行
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
流程总结:
就一句话:==所有已经放行的拦截器的afterCompletion 一定会执行==
SpringMVC的流程总结:
1、所有的请求,==前端控制器(DispatcherServlet),调用doDispatch==进行处理;
2、根据==HandleMapping中保存的映射信息==找到,处理当前请求的==,处理器执行链==(包含了拦截器)。
3、==根据当前处理器找到他的适配器==;
4、==拦截器的preHandle 先执行==
5、==适配器执行目标方法==
1)、ModelAttribute注解标注的方法提前执行
2)、执行目标方法的时候(确定目标方法的参数)
1)有注解:
2)没注解:
1)、看看是否是Model 、Map 或者其他的
2)、如果是自定义类型
1)先从隐含模型中看有没有,如果有就从隐含模型中拿
2)如果没有,看看是否是SessionAttributes标注的属性,如果是从session中拿,拿不到抛出异常
3)如果都不是,利用反射创建对象。
6、==拦截器的 postHandle 执行==
7、处理结果(==页面渲染流程==)
1)、如果有异常使用==异常解析器==处理异常,返回ModelAndView
2)、调用 ==render== 进行页面渲染
1)视图解析器通过视图名得到视图对象
2)、视图对象调用 render 方法;
3)、==执行拦截器的afterCompletion==
SpringMVC流程图: