为什么拦截器把正常请求也拦截了_原创007|搭上SpringBoot拦截器源码分析专车

前言

如果这是你第二次看到师长,说明你在觊觎我的美色!

点赞+关注再看,养成习惯

没别的意思,就是需要你的窥屏^_^

a1cba3a76f45170cff91c5f60c586d53.png

专车介绍

该趟专车是开往SpringBoot拦截器源码分析的专车

什么是拦截器?拦截器就是用来拦截指定的请求,在请求之前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。

拦截器最常用的使用场景就是鉴权,在请求开始之前,对当前请求进行权限校验,如果当前请求用户具备操作当前请求的权限,就对当前请求放行,允许执行业务逻辑;否则拦截当前请求,不执行业务逻辑。

专车问题

第一个问题:如何自定义拦截器?

第二个问题:拦截器的实现原理是什么?

专车示例

第一步:实现HandlerInterceptor接口

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

第二步:实现WebMvcConfigurer接口

@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SystemInterceptor).addPathPatterns("/**");}}

第三步:发送请求:localhost:8099/persons/,结果展示

preHandlelistpostHandleafterCompletion

如上可以看出拦截器的定义只需要的简单的两步操作就可以完成了,定义很简单,那么为什么重写addInterceptors方法就可以定义拦截器了呢?其中的实现原理又是什么样的?接下来会带着大家一步步揭开这层神秘的面纱。

专车分析

在SpringBoot请求处理源码分析一文中有提到创建RequestMappingHandlerMapping对象,下面来回顾一下。打开WebMvcAutoConfiguration自动配置类,会有对RequestMappingHandlerMapping Bean的声明

@Bean@Primary@Overridepublic RequestMappingHandlerMapping requestMappingHandlerMapping {// Must be @Primary for MvcUriComponentsBuilder to workreturn super.requestMappingHandlerMapping;}

创建RequestMappingHandlerMapping:WebMvcConfigurationSupport#requestMappingHandlerMapping

@Beanpublic RequestMappingHandlerMapping requestMappingHandlerMapping {RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping;mapping.setOrder(0);// 获取并设置拦截器mapping.setInterceptors(getInterceptors);mapping.setContentNegotiationManager(mvcContentNegotiationManager);mapping.setCorsConfigurations(getCorsConfigurations);return mapping;}

如上可以看到获取并设置拦截器的代码,那么是如何获取拦截器的呢?

获取拦截器:WebMvcConfigurationSupport#getInterceptors

protected final Object getInterceptors {if (this.interceptors == ) {// 创建拦截器注册器InterceptorRegistry registry = new InterceptorRegistry;// 新增拦截器addInterceptors(registry);// 添加拦截器registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));// 添加拦截器registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));// 获取拦截器列表this.interceptors = registry.getInterceptors;}// 返回拦截器列表return this.interceptors.toArray;}

如上需要重点分析的部分就是如何往注册器中添加拦截器

往注册器中添加拦截器:DelegatingWebMvcConfiguration#addInterceptors

@ConfigurationpublicclassDelegatingWebMvcConfigurationextendsWebMvcConfigurationSupport{// 创建WebMvcConfigurerComposite对象private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite;// 注入我们声明的WebMvcConfigurer接口实现,如上示例就是我们定义的WebMvcConfig@Autowired(required = false)publicvoidsetConfigurers(List configurers) {if (!CollectionUtils.isEmpty(configurers)) {// 将定义的webmvc配置类添加到configurers对象中this.configurers.addWebMvcConfigurers(configurers);}}@OverrideprotectedvoidaddInterceptors(InterceptorRegistry registry) {this.configurers.addInterceptors(registry);}}

先来看看将我们定义的webmvc配置类添加到configurers对象的实现,然后再来分析添加拦截器方法

添加自定义webmvc配置类:WebMvcConfigurerComposite#addWebMvcConfigurers

classWebMvcConfigurerCompositeimplementsWebMvcConfigurer{// 定义webmvc配置类集合private final List delegates = new ArrayList<>;publicvoidaddWebMvcConfigurers(List configurers) {if (!CollectionUtils.isEmpty(configurers)) {// 添加我们自定义的webmvc配置this.delegates.addAll(configurers);}}}

可以看到,该类中定义了一个webmvc配置类集合,将我们定义的webmvc配置类添加到这个集合当中,该部分操作是在程序启动的时候完成的。接下来看看添加拦截器部分代码

添加拦截器:DelegatingWebMvcConfiguration#addInterceptors

@OverrideprotectedvoidaddInterceptors(InterceptorRegistry registry) {this.configurers.addInterceptors(registry);}@OverridepublicvoidaddInterceptors(InterceptorRegistry registry) {// 遍历所有自定义webmvc配置类,然后调用配置类中重写的addInterceptors方法for (WebMvcConfigurer delegate : this.delegates) {// 调用自定义webmvc配置类中的addInterceptors,并传入注册器delegate.addInterceptors(registry);}}

再来看看我们定义的webmvc配置类

@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SystemInterceptor).addPathPatterns("/**");}}

我们拿着拦截器注册器,并调用它的添加拦截器方法,将我们自定义的拦截器添加到了拦截器注册器中

专车回顾

第一个问题:如何定义拦截器?定义拦截器需要实现两个接口HandlerInterceptor、WebMvcConfigurer

第二个问题:拦截器的实现原理?框架对外暴露web配置接口,用户需要实现web配置接口,实现想要的逻辑。框架在启动的时候会注入所有的web配置实现,在创建RequestMappingHandlerMapping对象的同时创建拦截器注册器,然后调用web配置实现类的方法并传入拦截器注册器,从而实现拦截器的注册功能。

专车总结

  • DelegatingWebMvcConfiguration类中会注入我们自定义的webmvc配置类,然后添加到WebMvcConfigurerComposite类中的webmvc配置类集合中
  • 创建RequestMappingHandlerMapping对象
  • 遍历自定义webmvc配置类集合,调用添加拦截器方法传入拦截器注册器
  • 调用自定义webmvc配置类的添加拦截器方法
  • 将自定义拦截器添加到拦截器注册器中

最后

师长,【java进阶架构师】号主,短短一年在各大平台斩获15W+程序员关注,专注分享Java进阶、架构技术、高并发、微服务、BAT面试、redis专题、JVM调优、Springboot源码、mysql优化等20大进阶架构专题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值