SpringMVC之拦截器

本文分析了SpringMVC中拦截器的工作原理,包括单个和多个拦截器的分类。拦截器的执行顺序遵循注册时的顺序,只有所有拦截器的preHandle方法返回true,才会继续执行后续代码。文章通过源码解读了从doDispatch方法开始的拦截器调用流程,包括applyPreHandle、applyPostHandle和processDispatchResult等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码分析

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");
    }
}

拦截器的分类

单个拦截器

图片.png

<!--注册拦截器-->
<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>

多个拦截器

图片.png

<!--注册拦截器-->
<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。
图片.png
以上图为例,对执行过程的源码进行一波的解析
首先,锁定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);
            }
        }
    }
}

拦截器的调用流程图
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值