• SpringMVC:拦截器拦截时机和原理


    测试

    先自定义一个拦截器

    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion");
        }
    }
    

    注册该拦截器

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/*");
        }
    }
    

    测试,访问接口:

    image-20210407143348235

    原理

    对DispatcherServlet的方法doDispatch打上断点

    image-20210407143648829

    getHandler不仅找到了当前请求的处理器,并且找到了对应的拦截器。

    断点继续往下走,在执行目标方法之前,调用了applyPreHandle方法,所以猜测这里就会调用拦截器preHandle方法,并且该方法如果返回false,就会return(被拦截)

    image-20210407144255910

    进入applyPreHandle方法,这里先顺序执行所有的拦截器的preHandle方法,只要有一个返回了false,就会调用triggerAfterCompletion方法,然后跳出循环

    image-20210407144807453

    triggerAfterCompletion方法:注意,这里从当前拦截器开始倒序执行前面以前已经执行过的拦截器的afterCompletion方法

    image-20210407145246760

    目标方法执行后,调用了applyPostHandle方法

    image-20210407145639651

    applyPostHandle源代码:这里会倒序执行所有的拦截器的postHandle方法

    image-20210407145735418

    继续往下看:

    image-20210407150203832

    processDispatchResult方法内部会倒序调用所有拦截器afterCompletion方法,意味着如果全部流程执行完了,中间没有任何异常,会调用afterCompletion方法

    如果中间过程中出现了异常,会调用triggerAfterCompletion方法,该方法仍然会倒序执行所有拦截器的afterCompletion方法。

    图示:

    image-20210407150725693

    总结

    1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】

    2、先来顺序执行 所有拦截器的 preHandle方法

    • 1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
    • 2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;

    3、如果任何一个拦截器返回false。直接跳出不执行目标方法

    4、所有拦截器都返回True。执行目标方法

    5、倒序执行所有拦截器的postHandle方法。

    6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

    7、页面成功渲染完成以后,也会倒序触发 afterCompletion

  • 相关阅读:
    javascript的字段值,私有变量,静态方法声明
    取得序列中某个点的范围边界
    使用wubi安装ubuntu11.04后无线网卡被禁用无法打开解决办法
    WEB前端性能优化
    jQuery的arrayLike
    在手机上安装BT5系统,没错就是破解无线密码的那个
    PHP在子类方法B调用父类的方法A时,不传参数时仍能得到方法B的名称
    讨厌的文本选区
    PHP遍历解析XML为一个数组
    “软工厂代码生成工具”的学习笔记
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14627812.html
Copyright © 2020-2023  润新知