回顾
上次讲到了拦截器的实现原理,即运用了AOP思想和责任链设计模式,对发起的请求进行拦截,并做处理。如果你自己也跟着写了demo的话,打断点的时候会发现,当return为true 时,会进入HandlerExecutionChain这个类,这个类是什么呢,我们今天就来研究一下。
HandlerExecutionChain
从字面的意思来看,估计你也会猜到这是个执行链,以下是部分属性。
private final Object handler; //处理器对象
private HandlerInterceptor[] interceptors; //拦截器数组
private List<HandlerInterceptor> interceptorList; //拦截器列表
显然这个类是由处理器对象和若干个拦截器组成的,组合使用就是责任链模式的一个实现。接着看几个主要的方法:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
详解:你会发现applyPreHandle()这个方法其实就是做着这样一个工作:按照列表中interceptor的顺序来执行它们的preHandle方法,直到有一个返回false。当返回false时,这时会调用triggerAfterCompletion方法,在这个方法中,this.interceptorIndex指向上一个返回true的interceptor的位置,所以在for循环中它会按逆序执行所有返回true的interceptor的afterCompletion方法。换言之,也就是对于任意的返回false的interceptor都不会执行afterCompletion方法。而且是中断之前所有的preHandle执行完成之后才会执行afterCompletion方法,如果你看过LZ之前的文章,那么此时正好解释了为什么说HandlerInterceptor接口中的afterCompletion()方法,先声明的Interceptor的afterCompletion方法后执行的原因!
接下来再看:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
详解:这个方法很简单,就是逆序执行所有interceptor的postHandle方法。
最后的triggerAfterCompletion()也是一样,就是从最后一次preHandle成功的interceptor处逆序执行afterCompletion,同样也解释了LZ上文说的postHandle 方法被调用的方向跟preHandle 是相反的,先声明的Interceptor 的postHandle 方法反而会后执行的原因!
HandlerMapping接口
其实,HandlerExecutionChain是通过HandlerMapping的getHandler方法返回的。可能会有点懵,HandlerMapping又是什么鬼?看一张图
上篇文章也说到了,拦截器是在controller之上的非系统级别,现在回头看一下springMVC执行流程,也就清楚了HandlerMapping是做什么的,来看一下代码:
HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
这个接口中只有这样一个方法,根据函数名,参数及返回值我们不难猜出这个接口的作用,就是根据request返回HandlerExecutionChain。至于HandlerMapping在springMVC中有多种实现,我们此处就不深究了。
对于getHandler最后的调度部分便是springMVC的最外层DispatcherServlet类了
DispatcherServlet类
DispatcherServlet类中调用HandlerMapping的getHandler的方法为getHandler(同名)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
从代码中不难看出整个逻辑就是依次判断servlet中的每个handlerMapping是否能够匹配该请求,直到找到那个匹配的然后返回处理结果。
对于HandlerExecutionChain的调用我们可以在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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
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);
}
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);
}
}
}
}
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) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
从上面代码中我们可以验证前面所说的HandlerInterceptor接口中三个方法的执行顺序:
preHandle是在找到处理handler对象的HandlerMapping之后,HandlerAdapter调度handler之前执行。
postHandle是在HandlerAdapter调度handler之后,DispatcherServlet渲染视图之前执行。
afterCompletion是在渲染视图结束后执行。
总结
引用道友的总结,即:
那么整个拦截器的处理过程我们便可以很清晰地分为两种情况,一种是所有拦截器preHandle都返回true的情况,另一种是有拦截器preHandle返回false的情况。
我们先假设我们有三个拦截器A,B,C,D。
对于第一种情况,那么在DispatcherServlet中分别依次调用HandlerExecutionChain类中applyPreHandle、applyPostHandle和triggerAfterCompletion方法,
那么所有方法的执行顺序为
A.pre -> B.pre -> C.pre -> D.pre
-> D.post -> C.post -> B.post -> A.post
-> D.after -> C.after -> B.after -> A.after
对于第二种情况,我们不妨设C拦截器的preHandle返回为false。
这时DispatcherServlet类调用HandlerExecutionChain类中applyPreHandle方法,然后由applyPreHandle调用triggerAfterCompletion方法,
那么执行情况如下
A.pre -> B.pre -> C.pre
-> B.after -> A.after
下回讲解过滤器!