springboot中的拦截器

一、拦截器介绍

拦截器可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情。拦截器的实现只需要实现 HandlerInterceptor 接口,并进行配置即可。
在这里插入图片描述
在这里插入图片描述
preHandler:进入请求方法之前执行;

postHandler:请求方法执行完成之后执行;

afterCompletion:视图渲染后执行。

二、单个拦截器执行顺序

如果只配置了一个拦截器,那么执行顺序应该是这样的:
preHandle -> dohandle(处理请求)-> postHandle -> render(渲染视图)-> afterCompletion

在 preHandle 方法中,它的返回值是 boolean 类型的,它的返回值影响着请求方法,以及 postHandle 和 afterCompletion 的执行。在 preHandle 中如果返回 false,那么后续的流程将不被执行。

三、多个拦截器执行顺序

当有多个自定义拦截器时这些方法的执行顺序则是不同,如果preHandler都返回true的情况下,preHandle方法按自定义拦截器配置的正序执行,而postHandle和afterCompletion方法按自定义拦截器配置的倒序执行;
在这里插入图片描述
如果某个拦截器返回false,postHandle方法都不会被执行,另外​只有返回true的拦截器的afterCompletion方法才会执行。

在这里插入图片描述

四、源码分析

一个请求打进来时,DispatcherServlet 中的 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;
                    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;
                        }
                    }
					// 执行拦截器的全部 preHandle 方法
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
 
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
 
                    this.applyDefaultViewName(processedRequest, mv);
                    // 执行拦截器的全部 postHandle 方法
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
				
				// 执行拦截器的全部 afterCompletion 方法
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                // 异常后,执行拦截器的全部 afterCompletion 方法
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                // 异常后,执行拦截器的全部 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);
            }
 
        }
    }

在mappedHandler.applyPreHandle() 方法中,通过HandlerInterceptor[] interceptors = this.getInterceptors(); 依序获得registry.addInterceptor()中加入的拦截器,for循环正序执行拦截器逻辑

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

而在mappedHandler.applyPostHandle()方法中,同样是通过HandlerInterceptor[] interceptors = this.getInterceptors(); `依序获得registry.addInterceptor()中加入的拦截器,不过在for循环中是倒序执行逻辑

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable 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);
            }
        }
 
    }

最后看一下mappedHandler.triggerAfterCompletion() 方法,同样for循环里是倒序执行逻辑

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable 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);
                }
            }
        }
    }

上面的拦截器都是按照我们配置中的顺序执行,那如果我们想要自定义顺序该怎么办呢, InterceptorRegistry 类的 addInterceptor 和 getInterceptors 方法源码如下,我们可以看到addInterceptor是将拦截器加入list集合,在getInterceptors 方法中this.registrations.stream().sorted(INTERCEPTOR_ORDER_COMPARATOR), 拦截器list集合按照 order 升序排序,默认order为0,可以在配置中用.order(int order)设置顺序。

public class InterceptorRegistry {
    private final List<InterceptorRegistration> registrations = new ArrayList();
    private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR;
 
    public InterceptorRegistry() {
    }
 
    public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
        InterceptorRegistration registration = new InterceptorRegistration(interceptor);
        this.registrations.add(registration);
        return registration;
    }
 
    public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
        WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
        InterceptorRegistration registration = new InterceptorRegistration(adapted);
        this.registrations.add(registration);
        return registration;
    }
 
    protected List<Object> getInterceptors() {
        return (List)this.registrations.stream().sorted(INTERCEPTOR_ORDER_COMPARATOR).map(InterceptorRegistration::getInterceptor).collect(Collectors.toList());
    }
 
    static {
        INTERCEPTOR_ORDER_COMPARATOR = OrderComparator.INSTANCE.withSourceProvider((object) -> {
            if (object instanceof InterceptorRegistration) {
                InterceptorRegistration var10000 = (InterceptorRegistration)object;
                ((InterceptorRegistration)object).getClass();
                return var10000::getOrder;
            } else {
                return null;
            }
        });
    }
}

五、总结

如果不设定拦截器顺序,preHandle 方法执行顺序与拦截器注册时顺序一致,postHandle 和 afterCompletion 方法执行顺序相反;如果我们给每个拦截器设置order ,则 preHandle 方法执行顺序是按照 order 升序执行,postHandle 和 afterCompletion 方法执行顺序反之。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot允许我们自定义拦截器来拦截请求并进行一些逻辑处理。下面是SpringBoot自定义拦截器的步骤: 1.创建一个拦截器类并实现HandlerInterceptor接口,该接口有三个方法:preHandle、postHandle和afterCompletion。其preHandle方法在请求处理之前被调用,postHandle方法在请求处理之后被调用,afterCompletion方法在视图渲染之后被调用。 2.在拦截器类上使用@Component注解将其注入到Spring容器。 3.创建一个配置类并实现WebMvcConfigurer接口,该接口有一个addInterceptors方法,可以用来添加自定义拦截器。 4.在addInterceptors方法添加自定义拦截器,并指定拦截的路径。 下面是一个简单的示例: 1.创建一个拦截器类并实现HandlerInterceptor接口: ```java @Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理之前进行逻辑处理 // 如果返回false,则请求不会被处理 return true; } } ``` 2.创建一个配置类并实现WebMvcConfigurer接口: ```java @Configuration public class MyWebMvcConfigurer implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 添加自定义拦截器,并指定拦截路径 registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } } ``` 在上面的示例,我们创建了一个名为MyInterceptor的拦截器类,并将其注入到Spring容器。然后,我们创建了一个名为MyWebMvcConfigurer的配置类,并在其添加了我们的自定义拦截器,并指定了拦截的路径为“/**”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值