一、准备工作
搭建好Spring MVC环境以后,我们创建一个拦截器:
名为MyInterceptor并实现HandlerInterceptor接口:
实现接口方法、便于观察我们只在控制台输出对应的方法名:
package com.jd.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
return true;
//初始实现方法代码中,此处返回的是false
//改为true的原因在下面分析时机时会详细说明
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
}
}
拦截器创建好以后,我们在spring xml文件中进行启用设置:
<mvc:interceptors >
<mvc:interceptor>
<!-- path属性用于限制能够匹配的请求 -->
<mvc:mapping path="/userinfo/*"/>
<bean class="com.jd.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
controller方法:
主页面请求链接:
目标页面:
发送请求:
二、拦截器执行时机
收到请求后DispatcherServlet类对象如下:
执行FrameworkServlet类service方法、
执行HttpServlet类service方法、
执行FrameworkServlet类doGet方法、
执行FrameworkServlet类processRequest方法、
执行DispatcherServlet类doService方法、
(详情参见Spring MVC请求执行过程)
执行DispatcherServlet类doDispatch方法、
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
/*mappedHandler = getHandler(processedRequest)
根据request得到一个HandlerExecutionChain对象
包含了mvc模块的拦截器即handlerInterceptor和真正处理请求的handler*/
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
/*1、调用applyPreHandle方法,可见此if分支在下面语句之前
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
所以此方法是在执行controller方法前执行*/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/*经过applyPreHandle方法(和拦截器preHandle方法)后
执行handle方法,完成controller方法
(这一行执行完我们会看到控制台输出controller)*/
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
/*2、完成controller方法后,调用applyPostHandle方法,可见此方法在语句
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
前执行*/
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
/*执行完applyPostHandle方法(和拦截器postHandle方法)后
调用processDispatchResult方法*/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
/*跳转自doDispatch方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
---------------------------------------*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, 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);
}
}
if (mv != null && !mv.wasCleared()) {
/*执行render方法,可见render方法是在执行完
applyPostHandle方法(和拦截器postHandle方法)后执行。
这一步执行完,响应的视图将处理完毕*/
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()) {
return;
}
if (mappedHandler != null) {
/*3、在render方法执行完后,执行triggerAfterCompletion方法*/
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
1、执行HandlerExecutionChain类中的applyPreHandle方法
/*跳转自doDispatch方法
if(!mappedHandler.applyPreHandle(processedRequest, response))
--------------------------------------------------*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取拦截器
HandlerInterceptor[] interceptors = getInterceptors();
//判断拦截器是否为空
if (!ObjectUtils.isEmpty(interceptors)) {
//遍历拦截器
for (int i = 0; i < interceptors.length; i++) {
//获取到我们的MyInterceptor拦截器
HandlerInterceptor interceptor = interceptors[i];
/*此时interceptor即为MyInterceptor类上转型对象
调用preHandle时出现多态现象
执行我们MyInterceptor类中的preHandle方法,并返回一个布尔类型结果
(这一行执行完我们就会看到控制台输出preHandle)*/
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
可见:
- 根据代码分析如果我们返回false,applyPreHandle方法
if(!interceptor.preHandle(request, response, this.handler))
为true,则进入if分支最后返回false,则doDispatch方法中if(!mappedHandler.applyPreHandle(processedRequest, response))
判断为true进入if分支将直接结束doDispatch方法。
- 所以我们可以根据需要进行处理,设置返回的值。
- 由上述:preHandle在Handler Method之前被调用,常用于实现权限。
2、执行HandlerExecutionChain类中的applyPostHandle方法
/*跳转自doDispatch方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
--------------------------------------------------*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
//获取拦截器
HandlerInterceptor[] interceptors = getInterceptors();
//判断拦截器是否为空
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
//获取到我们的MyInterceptor拦截器
HandlerInterceptor interceptor = interceptors[i];
/*此时interceptor即为MyInterceptor类上转型对象
调用postHandle时出现多态现象
执行我们MyInterceptor类中的postHandle方法
(这一行执行完我们就会看到控制台输出postHandle)*/
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
可见:
- postHandle方法在controller方法执行后,processDispatchResult方法(和render)方法执行前执行
- controller方法执行后的视图将传入postHandle
- 由上述,postHandle方法常用于对请求域中的属性或视图做出修改
3、执行HandlerExecutionChain类中的triggerAfterCompletion方法
/*跳转自processDispatchResult方法
mappedHandler.triggerAfterCompletion(request, response, null);
--------------------------------------------------*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
//获取拦截器
HandlerInterceptor[] interceptors = getInterceptors();
//判断拦截器是否为空
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
//获取到我们的MyInterceptor拦截器
HandlerInterceptor interceptor = interceptors[i];
try {
/*此时interceptor即为MyInterceptor类上转型对象
调用afterCompletion时出现多态现象
执行我们afterCompletion类中的afterCompletion方法
(这一行执行完我们就会看到控制台输出afterCompletion)*/
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
可见:
- afterCompletion方法在render方法执行完以后执行
- 此时响应的视图已经处理完毕
- 所以:afterCompletion方法常用于释放资源
至此,拦截器方法执行完毕
三、结果
响应页面
控制台输出:
输出顺序即为对应方法执行顺序