目录

一、原因

二、自定义拦截器

三、源码解析

doDispatch()方法

applyPreHandle()方法

postHandle()方法

afterCompletion()方法

拦截器链的由来

getHandler(processedRequest)方法

mapping.getHandler(request)方法

getHandlerExecutionChain(handler, request)

chain.addInterceptor(interceptor)

interceptors的值


一、原因

在之前,总是对过滤器、拦截器、监听器、MethodInterceptor(AOP)总是懵懵懂懂,不明白什么时候用过滤器,什么时候用拦截器好,只是工作中需要了就去百度,然后对比半天,找个看着差不多的把他写的代码粘过来放到自己的项目里再调试。

但是没有去思考它是怎么实现的,是谁调用的,为什么我这么写就可以调到?今天就来详细的介绍一下。

二、自定义拦截器

首先需要知道的是HandlerInterceptor是属于SpringMVC的。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_java

springboot中拦截器的注册还是比较方便的。大概下面两个步骤:

第一步,创建拦截器DemoInterceptor类:

可以实现接口HandlerInterceptor,也可以继承HandlerInterceptorAdapter类,两种方法一样。

package com.demo.aop;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class DemoInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("DemoInterceptor:" + request.getRequestURL().toString());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

}

第二步,配置拦截器:

package com.demo.aop;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 配置拦截器
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new DemoInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/static/login.html");
    }
    
    
}

至此我们就自定义了自己的拦截器,在HandlerInterceptor中有三个方法,我们可以在自定义的拦截器中重写这三个方法来实现自己的业务逻辑,从下图可以看出这三个方法的执行顺序。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_02

注意点:拦截器中方法的执行顺序是 preHandle -> Controller -> postHandle -> afterCompletion,只有preHandle返回true,才会执行后面的方法

三、源码解析

为什么说HandlerInterceptor是属于SpringMVC,因为这三个方法都是在SpringMVC的DispatchServlet#doDispatch()方法中调用的,对于DispatchServlet类大家应该都非常熟悉了。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_03

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 {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    // 获取拦截器链HandlerExecutionChain
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.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 ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
                    // 1、执行preHandle()方法
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    // 2、执行controller中的方法
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    // 3、执行postHandle()方法
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                // 4、调用afterCompletion()方法
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                // 4、内部调用了afterCompletion()方法,就算报异常也会调用afterCompletion()方法
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                // 4、内部调用了afterCompletion()方法,就算报异常也会调用afterCompletion()方法
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

applyPreHandle()方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_04

applyPostHandle()方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_05

afterCompletion()方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_06

拦截器链的由来

拦截器实现的核心是拦截器链,我们来看一下拦截器链是如何形成的,即HandlerExecutionChain类。

在上面的三个方法中,都是通过this.getInterceptors()方法获取HandlerInterceptor数组,数组又是将拦截器List集合转化的,那么拦截器又是什么时候放入到List集合中的呢?

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_07

关键还在doDispatch()方法中,通过getHandler(processedRequest)获取HandlerExecutionChain,在这个方法中将自定义拦截器添加到interceptorList中的。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_java_08

getHandler(processedRequest)方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_09

mapping.getHandler(request)方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_10

getHandlerExecutionChain(handler, request)

真正获取拦截器链的方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_java_11

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_12

chain.addInterceptor(interceptor)

调用chain.addInterceptor(interceptor)方法添加到interceptorList集合中,至此我们就找到了拦截器List集合的来源。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_java_13

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_14

但是我们自定义的拦截器又是什么时候加载的呢?还记得我之前说springboot初始化会调用initApplicationContext()方法么?在下图debug中我们看到了自己定义的DemoInterceptor拦截器,那么interceptors的值从哪里来?

interceptors的值

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_java_15

在当前类中搜索,发现是在setInterceptors()方法中添加的,但是参数是传入的,在此处打断点一探究竟。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_interceptor_16

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_spring_17

进入到requestMappingHandlerMapping()方法中,发现是在创建这个对象实例化时,调用getInterceptors()获取的自定义拦截器。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_拦截器_18

getInterceptors()方法

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_拦截器_19

addInterceptors(registry)执行会调用我们写的拦截器配置类InterceptorConfig类,在其中配置了我们自己的拦截器。

HandlerInterceptorAdapter 那个maven handlerinterceptor原理_sed_20

至此我们能够大体了解拦截器的调用逻辑,以及拦截器的由来,调用等原理。