拦截器是基于反射还是动态代理来实现的?
创始人
2025-05-29 14:21:51
0

 

话说拦截器,功力不够,体会不到哪里用到了反射或者动态代理,用反射也就是 Spring 创建拦截器对象的时候,不能说这就是基于反射了吧?那动态代理在拦截器中连个影子都找不到,哪里有?

当你不知道答案的时候,就看看源码,源码不会忽悠人

用户请求到 DispatherServlet 中,DispatherServlet 调用 HandlerMapping 查找 Handler,HandlerMapping 返回一个拦截器链(HandlerExecutionChain),springmvc 中的拦截器是通过 HandlerMapping 发起的。

在企业开发,使用拦截器实现用户认证(用户登陆后进行身份校验拦截),用户权限拦截和方法性能监控等。

拦截器在 SpringMVC 中是最好理解的,在创建 RequestMappingHandlerMapping 对象时候进行拦截器收集,RequestMappingHandlerMapping 对象就负责处理我们写的 Controller,Controller收集过程在他重写的 afterPropertiesSet 方法下,这个方法是 Spring 进行对象 init 阶段调用的。

创建 RequestMappingHandlerMapping 在 WebMvcConfigurationSupport 中,他是由 @Bean 方式创建的,详细可以看源码,在这个过程中,会调用子类的 addInterceptors 进行拦截器对象收集,这里的子类通常都是我们编写的了,到这里就熟悉了吧。

@Override
protected void addInterceptors(InterceptorRegistry registry) {super.addInterceptors(registry);registry.addInterceptor(new HandlerInterceptor(){});
}

而 SpringMVC 调用拦截器时机有三个地方,这三个时机会分别调用下面三个方法。

default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {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 {
}

HandlerInterceptor接口的方法说明

 

HandlerInterceptor接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

preHandle():这个方法在业务处理器处理请求之前被调用,SpringMVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会是调用当前请求的 Controller 方法。这个阶段是在 DispatcherServlet 中调用的,DispatcherServlet 是一个 Servlet,一个请求最先进入的地方,当然前面可能还有过滤器,Dispatcher 意味分发,也就是 DispatcherServlet 负责把请求分发给对应的 Controller,并且也会先调用拦截器。

postHandle():这个方法在当前请求进行处理之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 是相反的,也就是说先声明的 Interceptor 的 postHandle 方法反而会后执行。

afterCompletion():该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。afterCompletion方法被调用的方向和perHandle也是相反的,先声明的Interceptor的afterCompletion方法后执行。

注意看 doDispatch 方法,可以看到下面这句代码,apply(运用)、Pre(前)、Handle(处理),这里就是调用拦截器中 preHandle 方法。

if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;
}

而方法也简单,就是遍历所有拦截器,只要有一个拦截器返回 false,则请求终止。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptorList.size(); i++) {HandlerInterceptor interceptor = this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}return true;
}

下一个时机在同样在 DispatcherServlet 中的 doDispatch 方法下,调用所有拦截器的 postHandle 方法,这个时候 Controller 已经调用完毕了,如果继续用 response 对象做输出,会被追加到原本返回的信息后面,如果你使用的模板引擎,这时候也可以更改 Model 中的数据或者视图名称。

mappedHandler.applyPostHandle(processedRequest, response, mv);

最后一个时机在 processDispatchResult 方法下,调用 afterCompletion,这时候不能在更改 Model 中的数据或者视图名称,但是也可以做输出,他用来做一些资源清理,这个调用顺序和拦截顺序相反,就是先被调用 preHandle 的拦截器会最后才被调用 afterCompletion。

请问这个过程哪有什么动态代理?

多读书啊,小伙子们,要不然全是“bug”。

 

SpringMVC 拦截器的实现方式

第一种方式是要定义的 Interceptor 类要实现了 Spring 的 HandlerInterceptor 接口。

第二种方式是继承实现了 HandlerInterceptor 接口的类,比如 Spring 已经提供的实现了 HandlerInterceptor 接口的抽象类 HandlerInterceptorAdapter。

记住三句话

  1. 监听应用(应用于整个程序应用)

  2. 过滤请求/资源(应用于容器)

  3. 拦截方法(相较于过滤器更细粒化的拦截,应用于方法)

作用范围从小到大,加载顺序也是。拦截器是实现 AOP 的一种策略

对比与联系

  1. 拦截器是基于 java 反射(Spring)机制来实现的,而过滤器是基于函数回调来实现的。

  2. 拦截器不依赖 servlet 容器,过滤器依赖于 servlet 容器。

  3. 拦截器只对 Action 起作用,过滤器可以对所有请求起作用。

  4. 拦截器可以访问 Action 上下文和值栈中的对象,过滤器不能。

  5. 在 Action 的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。

 

 

 

 

 

相关内容

热门资讯

优秀班主任主要事迹10篇汇总 ... 篇一:  本人自2009年参加工作以来,一直担任班主任工作,本人在班级管理、教学和德育工作方面均表现...
最新或2023(历届)初中模范... 篇一:优秀班主任先进事迹材料  我从事教育教学工作二十一年了,多年来,我和广大教师一样,热爱教育事业...
最新或2023(历届)县优秀班...   爱岗敬业呕心化春雨 倾情撑蓝天  记玉龙县优秀教师 xxx  xxx,女,纳西族,xxx年xx月...
最新或2023(历届)优秀班主...   篇一:优秀班主任先进事迹  ***,男,汉族,1973年8月出生于安徽明光市,现为经济管理学院综...
电影南京南京观后感大全 关于电...  【篇一】  5.1号走进莱蒙的东方国际影城观看这部期待了很久的电影南京南京,一定要去看这个片子原因...
Python tkinter ... *18.2.23 dchars(args) *args传递的参数有3个: ࿰...
2021年瑶海区信息学初中组 2021年瑶海区信息学初中组 1.完全立方数(cube) 问题描述 小瑶酷爱数学,这两天在研究完全立...
优秀班主任推荐材料表材料 优秀... 我叫,自担任班主任以来,关爱学生,爱岗敬业,尽职尽责,严于律己,班级教育教学管理 成绩 突出.特别....
乡镇妇联主席先进事迹 乡镇妇联...  篇一:  ***,最新或2023(历届)12月任**镇妇联主席.三年来,她以加强理论和业务学习为立...
最新或2023(历届)先进基层... 社区先进基层党组织事迹材料  桥西社区自创先争优活动开展以来,社区党总支从广大居民需求出发,主打文化...
脱贫攻坚主题党日活动方案 牢记...  今年10月17日,是我国第3个扶贫日,也是第24个国际消除贫困日。推进脱贫攻坚是深入扎实持久开展“...
4年功能测试,我一进阶pyth... 目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目...
四月学校支部主题党日活动方案 ...  【四月学校支部主题党日活动方案一】  各支部:  根据郧学组办发〔最新或2023(历届)〕3 号文...
【Unity工具,简单应用】P... 【Unity工具,简单应用】Photon + PUN 2,做一个...
村党支部主题党日活动方案 村党... 【村党支部主题党日活动方案一】  为进一步丰富基层党组织活动的内容与形式,推动党组织生活规范化、正常...
最新或2023(历届)学校主题... 【最新或2023(历届)学校主题党日活动方案一】  为增强学生党员意识,弘扬长征精神,加深广大党员对...
最新或2023(历届)主题党日...  【最新或2023(历届)主题党日活动设计方案一】  为深入开展“两学一做”学习教育,根据市委要求,...
最新或2023(历届)党支部主...  【党支部主题党日活动方案一】  一、活动主题  纪念百色起义,龙州起义XXX周年  二、活动意义 ...
有关最新或2023(历届)妇联...  【妇联母亲节活动方案一】  一、指导思想  认真学习党的十八大精神,全面贯彻落实科学发展观,以健康...
【DDIM精读】公式推导加代码... 【DDIM精读】公式推导加代码分析。1.前言:ddim总览2.均值(μ\...