本文以一个通过正常注册拦截器流程注册拦截器失败的实际场景,来带领大家阅读源码,体会Spring的HandlerInterceptor拦截器整个工作流程
简单认识
org.springframework.web.servlet.HandlerInterceptor是Spring框架中的一个接口,用于拦截处理程序(Handler)的请求和响应。它允许开发人员在请求处理程序执行之前和之后执行自定义的预处理和后处理逻辑。 HandlerInterceptor接口定义了三个方法:
- preHandle:在请求处理程序执行之前调用。可以用于进行权限验证、日志记录等操作。如果该方法返回false,则请求将被中断,后续的拦截器和处理程序将不会被执行。
- postHandle:在请求处理程序执行之后、视图渲染之前调用。可以对请求的结果进行修改或添加额外的模型数据。
- afterCompletion:在整个请求完成之后调用,包括视图渲染完毕。可用于进行资源清理等操作。 通过实现HandlerInterceptor接口,可以自定义拦截器,并将其注册到Spring MVC的配置中。拦截器可以拦截指定的URL或者所有请求,并在请求的不同阶段执行相应的逻辑。
正常的拦截器注册流程
定义一个拦截器,实现org.springframework.web.servlet.HandlerInterceptor接口
如:
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// ...
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
// ...
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
// ...
}
}
定义配置类,实现WebMvcConfigurer,实现addInterceptors进行拦截器注册
@Configuration(proxyBeanMethods = false)
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// ...
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns(HOTSWAP_ALL_SERVICE)
.addPathPatterns(hsAddPaths)
.excludePathPatterns(commonExcludePaths);
// ...
}
}
而有时候通过这种方式注册不成功。
我们先来说一下说一下HandlerInterceptor的工作机制。首先以上描述的是拦截器的注册过程。
然后再来看一下注册的拦截器存储在哪里,以及如何被使用的。
存储已注册拦截器的位置
查看接口方法org.springframework.web.servlet.config.annotation.WebMvcConfigurer#addInterceptors
的调用之处,位于类org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
里面,其是WebMvcConfigurationSupport
的子类
WebMvcConfigurationSupport的一个子类,它检测并委托给所有WebMvcConfigurer类型的bean,允许它们自定义WebMvcConfigurationSupport提供的配置。这是@EnableWebMvc实际导入的类。
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors
方法:
@Override
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
可以看出,这是从我们注册的WebMvcConfigurer实现类中,通过传入的InterceptorRegistry实例搜集拦截器,而调用该方法的地方位于
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping
,实际是其默认子类DelegatingWebMvcConfiguration
进行注册RequestMappingHandlerMapping bean 的行为,在其方法中调用了org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors
方法,解析InterceptorRegistry里面添加的拦截器。
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors
* Provide access to the shared handler interceptors used to configure
* {@link HandlerMapping} instances with.
* <p>This method cannot be overridden; use {@link #addInterceptors} instead.
*/
protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
Interce