请你谈谈:spring拦截器的应用-preHandle postHandle afterCompletion执行顺序问题的讨论?

首先我们,给出一个demo来看下拦截器方法执行顺序:

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("1-1 preHandle: ");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("2-1 postHandle: ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("3-1 afterCompletion: ");
    }
}

import org.springframework.beans.factory.annotation.Autowired;
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 WebmvcConfig implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
}

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        System.out.println("controller:");
        return "hello, zhaoshuai-lc";
    }
}

在这里插入图片描述
在Spring MVC中,拦截器(Interceptor)的三个主要方法preHandlepostHandleafterCompletion的执行顺序是严格规定的,这些方法的执行时机和顺序对于理解Spring MVC的请求处理流程至关重要。以下是这三个方法的执行顺序的详细解释:

执行顺序

  1. preHandle

    • 调用时间:该方法在请求处理之前执行,即Controller方法调用之前。
    • 执行顺序:如果有多个拦截器,它们会按照配置的顺序(即拦截器数组中的正向顺序)依次执行。
    • 返回值
      • 返回true:表示当前拦截器处理通过,请求会继续传递给下一个拦截器(如果有的话),或者如果没有其他拦截器了,就会传递给Controller处理。
      • 返回false:表示当前拦截器拦截请求,不会继续执行后续的拦截器或Controller方法,而是直接中断执行流程,并会根据情况(如配置)执行afterCompletion方法(但需要注意的是,不是所有返回false的拦截器都会执行afterCompletion,这取决于拦截器的具体配置和是否发生异常)。
      • 在这里插入图片描述
        在这里插入图片描述
  2. postHandle

    • 调用前提preHandle方法必须返回true,即请求被正常放行到Controller方法执行之后,但在DispatcherServlet进行视图渲染之前。
    • 调用时间:Controller方法处理完请求并返回ModelAndView之后,但在视图渲染之前。
    • 执行顺序:如果有多个拦截器,它们会按照配置的逆序(即拦截器数组的反向顺序)执行。
    • 注意:如果Controller方法执行过程中抛出异常,将跳过postHandle方法,直接执行afterCompletion方法。

总结

方法名调用时机执行顺序(多个拦截器时)主要作用
preHandle请求处理之前,Controller方法调用之前正向顺序决定是否继续执行后续的拦截器或Controller
postHandleController方法处理完请求后,视图渲染前反向顺序(如果执行)对ModelAndView进行操作(如果需要)
afterCompletion(不完备说法)整个请求处理结束之后,包括视图渲染之后反向顺序资源清理工作,如关闭数据库连接等

这个执行顺序和规则是Spring MVC框架中拦截器机制的核心,理解和掌握它们对于开发高质量的Web应用至关重要。

关于拦截器preHandle方法返回false时,afterCompletion方法会被调用的描述是不准确的。在Spring MVC的拦截器机制中,如果preHandle方法返回false,则请求处理流程会立即中断,但并不会立即调用afterCompletion方法。

实际上,afterCompletion方法的调用时机是在整个请求处理流程结束后,无论是否发生了异常。但是,当preHandle方法返回false时,请求处理流程尚未到达处理器的执行阶段,因此后续的拦截器(如果有的话)的postHandleafterCompletion方法,以及处理器的执行都不会发生。

只有当请求处理流程完全结束,且Spring MVC确定不再有其他拦截器或处理器的逻辑需要执行时,才会逆序调用每个拦截器的afterCompletion方法。但是,由于preHandle的返回值导致了流程中断,所以当前拦截器之后的拦截器(如果有的话)的afterCompletion方法将不会被调用,而当前拦截器之前的拦截器(如果有的话)的afterCompletion方法将会按照逆序被调用。

重要的是要理解,afterCompletion方法的主要目的是进行资源清理或记录日志等操作,它应该能够在请求处理流程的任意点之后被调用,以确保资源的正确释放或日志的完整记录。但是,由于preHandle的返回值导致了流程中断,所以与当前请求直接相关的处理器和后续拦截器的逻辑将不会被执行,但之前的拦截器(如果有的话)的afterCompletion方法仍然会被调用。

总结一下,如果preHandle方法返回false,则:

  1. 当前拦截器之后的拦截器和处理器的逻辑将不会被执行。
  2. 当前拦截器之前的拦截器的afterCompletion方法(如果有的话)将按照逆序被调用。
  3. 当前拦截器的afterCompletion方法(如果有的话)通常不会被立即调用,但会在整个请求处理流程结束后,与之前的拦截器一起被调用(前提是它们之前没有被异常中断)。然而,由于preHandle的返回值,与当前请求直接相关的逻辑已经中断,所以当前拦截器的afterCompletion方法中的代码应该处理这种中断情况,并释放任何已分配的资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值