源码分析
public interface HandlerInterceptor {
//处理器方法执行前
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//如果该拦截器执行完后,还调其他拦截器或者还有业务处理,就返回true,否则返回false
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 {
}
}
对于我们使用拦截器时,需要实现上面的这个接口,并重写此接口中的方法,即可调用对应的拦截方法。
public class YourInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行your拦截器---------preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("执行your拦截器---------postHandler");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行your拦截器---------afterCompletion");
}
}
拦截器的分类
单个拦截器
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--
/**的意思是所有文件夹及里面的子文件夹
/*是所有文件夹,不含子文件夹
/是web项目的根目录
-->
<mvc:mapping path="/**"/>
<!-- 需排除拦截的地址 -->
<!-- <mvc:exclude-mapping path="/userController/login"/> -->
<bean class="com.yara.mvc.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
多个拦截器
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--/**表示全部路径-->
<mvc:mapping path="/**"/>
<bean class="com.yara.mvc.interceptor.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--/**表示全部路径-->
<mvc:mapping path="/**"/>
<bean class="com.yara.mvc.interceptor.YourInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
因为有多个拦截器,所以生成了拦截器链,我们就要考虑多个拦截器的执行顺序了.
拦截器执行顺序:与其注册顺序一致,即拦截器1写在拦截器2的前头,那就先执行拦截器1。
以上图为例,对执行过程的源码进行一波的解析
首先,锁定DispatcherServlet
类中的doDispatch方法,
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//在这里调用applyPreHandle方法,在处理器执行前执行。
//preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//这里是执行处理器代码,也就是业务代码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//在这里会调用applyPostHandle,在处理器执行后执行。
//postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//最后会执行这个方法,在该方法中会调用triggerAfterCompletion方法,调用afterCompletion进行资源的清理。
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()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
执行HandlerExecutionChain
的applyPreHandle方法,执行拦截器的preHandle方法,对该方法返回值进行判断,只有所有的拦截器的preHandle方法返回值都为true,才会继续执行后面的代码,否则就直接执行afterCompletion(清理资源),结束运行了。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取全部的拦截器
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//遍历拦截器,并且调用preHandle方法,
//如果是true,则继续循环,调用下一个拦截器的preHandle方法,进行判断
//如果是false,则执行AfterCompletion,清理资源
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
接着调用applyPostHandle方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
//在这里会调用postHandle,也就是自定义的后置拦截器进行拦截操作
interceptor.postHandle(request, response, this.handler, 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.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
//在这里,会调用triggerAfterCompletion方法,以调用afterCompletion来清理资源
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
//调用afterCompletion方法,进行资源清理
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
拦截器的调用流程图