springmvc拦截器工作源码

6 篇文章 0 订阅

当一个请求到达后,会调用DispatcherServlet的doDispatch( )方法,在此方法中调用拦截器,调用方法栈如下:

这里写图片描述

doDispatch( )方法源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try{
        HandlerExecutionChain mappedHandler = null;
        ...
        //执行interceptor的preHandle
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
        }

        //执行实际的Controller
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        ...
        //执行interceptor的postHandle
        mappedHandler.applyPostHandle(processedRequest, response, mv);
    }catch (Exception ex) {
        dispatchException = ex;
    }
    catch (Throwable err) {
        dispatchException = new NestedServletException("Handler dispatch failed", err);
    }
    ...
    //渲染页面并执行afterCompletion
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    ...
}

HandlerExecutionChain是一个由拦截器组成的一个chain链,是一个责任链模式,内部保存了拦截器的集合,这个集合和filter过滤器一样,是在请求到来后,根据url进行正则匹配,从所有的拦截器中选出符合规则的,然后加入到集合中。

public class HandlerExecutionChain {
    private final Object handler;

    private HandlerInterceptor[] interceptors;

    private List<HandlerInterceptor> interceptorList;

    private int interceptorIndex = -1;

    ...

HandlerExecutionChain的applyHandle方法如下:

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];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}

执行逻辑是:按照拦截器的顺序从前向后执行preHandle方法,如果有一个拦截器返回了false,那么将不再继续执行当前拦截器及其之后拦截器的preHandle,而是按拦截器逆序执行afterCompletion方法:

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--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}

triggerAfterCompletion方法会吞掉所有异常,保证拦截器的afterCompletion方法全部得到执行。注意triggerAfterCompletion方法的循环边界,是 interceptorIndex,而不是 interceptors.length,也就是说只执行那些preHandle方法返回true的拦截器。之后return false。不再继续执行真正的Controller。

如果拦截器均返回了true,那么继续执行Controller的逻辑,然后按逆序执行拦截器的postHandle方法:

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--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}

如果在执行preHandle和postHandle时抛出了异常,那么会把异常记录下来,然后执行processDispatchResult方法;如果一切顺利,那么也会执行processDispatchResult方法:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    boolean errorView = false;

    if (exception != null) {
        ...
        //处理错误页面
        mv = processHandlerException(request, response, handler, exception);
        ...
    }

    ...
    //写回浏览器结果
    render(mv, request, response);

    ...
    //执行拦截器的afterCompletion方法
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

总结一下:当一个请求到达之后,springmvc会根据请求的url找出相匹配的拦截器,组装成一个责任链,按照拦截器顺序依次执行其preHandle方法,执行完毕之后,继续执行具体的Controller,当Controller执行完成后,会逆序执行拦截器的postHandle方法,之后渲染页面,最后逆序 执行afterCompletion方法。如果在执行preHandle的过程中,有任意一个interceptor返回了false,那么请求将不再继续向下执行,在逆序执行完之前返回true的拦截器的afterCompletion方法后,结束对请求的处理。如果在preHandle和postHandle方法中抛出了异常,那么spring会将异常捕捉,记录异常信息,不再继续执行拦截器的处理,而是执行渲染页面并执行那些成功执行过preHandle方法的拦截器的afterCompletion方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值