spring boot 2.x 添加拦截器配置未生效的问题

背景: 今天有一个需求需要拦截除登录相关请求以外的所有请求,并查看request 中是否包含指定的信息,而自然就想到了使用拦截器就可以轻松实现

编写拦截器,获取请求头信息中的test,并打印出来

@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {

        String testData = request.getHeader("test");
        System.err.println(testData);
        return true;
    }
}

添加拦截器

@Configuration
public class AuthorizationConfig implements WebMvcConfigurer {

    @Autowired
    AuthorizationInterceptor authorizationInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
    }
}

而当我打上断点后,这里却出现了2个问题

  • 请求却没有到这里来
  • 前端反馈说Swagger文档地址也打不开了

到这里说明我们的配置并没有生效,或者说都失效了,那么有可能是什么原因导致我们的拦截器配置失效呢?

突然想起为支持跨域而添加的配置,如下:

@Configuration
public class CorsConfig extends WebMvcConfigurationSupport {
    
   /* @Autowired
    private AuthorizationInterceptor authorizationInterceptor;*/
    
    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("*").maxAge(3600);
    }
}

这里我们也没发现什么异常的地方,只能往SpringBoot 自动加载WebMvc配置的地方看了,默认情况下,SpringBoot是启用WebMvcAutoConfiguration,我们打开WebMvcAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
//@ConditionalOnClass注解表示在环境中存在指定的类才加载此配置
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
//@ConditionalOnMissing注解表示在环境中出现了指定的类则不加载此配置
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
      ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

   public static final String DEFAULT_PREFIX = "";

   public static final String DEFAULT_SUFFIX = "";

   private static final String[] SERVLET_LOCATIONS = { "/" };
    ....
}

结论: 也就是说我们为添加跨域支持时继承了WebMvcConfigurationSupport,(可以使用webmvcconfigureAdapter ,但是因为我使用的是SpringBoot2.x 以上的版本,该抽象类已经被废弃)而在WebMvc 自动装配的配置类中,指定了WebMvc的加载条件

  • 当环境中(IOC容器)存在Servlet、 DispatcherServlet、 WebMvcConfigurer 时加载WebMvc配置
  • 当环境中存在WebMvcConfigurationSupport Bean时不加载此配置,也就是说不能有WebMvcConfigurationSupport

所以这也就解释了我们新添加的拦截器不生效的原因了!

到这里我们还有如下2个问题:

  • 如何添加自定义的拦截器
  • Swagger文档访问不了的情况

这2个问题本身就是我们的WebMvc配置因为我们继承使用WebMvcConfigurationSupport 未被加载的原因,查看WebMvcConfigurationSupport 源码发现,在Spring 要获取拦截器链时会调用一个交给子类实现的钩子方法,如下:

//SpringBoot 启动时会调用该方法获取拦截器
protected final Object[] getInterceptors(
      FormattingConversionService mvcConversionService,
      ResourceUrlProvider mvcResourceUrlProvider) {
   if (this.interceptors == null) {
      InterceptorRegistry registry = new InterceptorRegistry();
       //这里就是交给子类实现的钩子方法,空实现
      addInterceptors(registry);
      registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
      registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
      this.interceptors = registry.getInterceptors();
   }
   return this.interceptors.toArray();
}

//交给子类实现的钩子方法
protected void addInterceptors(InterceptorRegistry registry) {
    
}

所以我们可以直接在添加跨域配置的配置类中重写addInterceptors方法,并在里面添加swagger的HTML的映射

@Configuration
public class CorsConfig extends WebMvcConfigurationSupport {
    
    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;
    
    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("*").maxAge(3600);
    }
    //这里添加自定义的拦截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }
}

到这里请求能够到达我们自定义的拦截器中,swagger接口文档地址也能够正常访问!

总结:

  • @ConditionalOnClass注解表示在环境中存在指定的类才加载此配置
  • @ConditionalOnMissing注解表示在环境中出现了指定的类则不加载此配置

你可能感兴趣的:(spring boot 2.x 添加拦截器配置未生效的问题)