允许 Spring 在不同的 jars 中有多个 WebMvcConfigurer 实现

use*_*155 1 java spring-mvc interceptor spring-boot spring-web

使用 Spring Web 时,在这种情况下,对于其余端点和使用 Spring Boot 2,我可以通过实现WebMvcConfigurer接口为我的应用程序配置拦截器:

@Configuration
public class SpringWebConfig implements WebMvcConfigurer
{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor).addPathPatterns("/api/endpoint/**");
    }
}
Run Code Online (Sandbox Code Playgroud)

我通过执行以下操作以自动方式将此拦截器添加到我的大多数应用程序中:

  1. 创建一个“common-jar”,将上面的接口放在 package 下
    com.company.api
  2. 在每个应用程序中,将包添加com.company.api到 api 扫描。

这个 common 包还包含 Interceptor 和实用程序类来使这个拦截器工作,所以实际上,添加这个 common-jar 会自动将他的拦截器添加到应用程序中的所有操作中,这与 Spring 本身所做的概念类似:添加依赖项改变了 Spring 的默认配置。

我现在面临的问题是这种方法不能扩展到第二个 jar 中的第二个拦截器,因为我已经使用了 WebMvcConfigurer实现。我不能有两个。

我在考虑可能使用某种复合配置器模式,我们循环遍历每个配置器,收集所有拦截器,然后添加一次,但不幸的是 Spring 不允许这样做。我有哪些选择?

目前,我采用的方法是WebMvcConfigurer在每个需要它的应用程序中复制界面。当事情发生变化时,我感到很难过,我必须在每个应用程序中更改相同的代码片段。

Ken*_*han 6

如果我正确理解您的问题,基本上您想Interceptors在多个 JAR 中定义一些共同点,以便应用程序可以Interceptors通过简单地将这些 JAR 包含到他们的应用程序中来激活它们?

我在考虑可能使用某种复合配置器模式,我们循环遍历每个配置器,收集所有拦截器,然后添加一次,但不幸的是 Spring 不允许这样做。我有哪些选择?

好吧,如果实现 A 返回一个只有拦截器 A 的注册表,而实现 B 返回一个只有拦截器 B 的注册表,那么 spring 会将两个注册表合并到一个包含 A 和 B 的超级注册表中,或者它只是选择一个,或者它会抛出没有唯一的 bean 定义的错误?

实际上,Spring 已经实现了这个特性。当有多个WebMvcConfigurerbeans 时,Spring 只是简单地将它们一一循环并调用它们的配置方法。所以最终结果是InterceptorRegistry将包含所有拦截器。

如果客户端应用程序只需要激活某些WebMvcConfigurer,它可以简单地排除那些包含WebMvcConfigurer他们不想要的JAR 。

为了让这个想法更进一步,允许应用程序控制Interceptors激活到拦截器级别,您甚至可以在每个公共 JAR 中执行以下操作:

@Configuration
public class SpringWebConfig implements WebMvcConfigurer {

    //Make sure the HandlerInterceptor implementation in this JAR is a bean (e.g mark it as @Component)
    @Autowired
    private List<HandlerInterceptor> interceptors;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        for(HandlerInterceptor interceptor : interceptors){
            registry.addInterceptor(interceptor).addPathPatterns("/api/endpoint/**");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在客户端应用程序中,使用includeFilters/ excludeFiltersin@ComponentScan自定义要包含哪些拦截器。例如,要禁用某些Interceptors,您可以执行以下操作:

@ComponentScan(
    basePackages = {"com.company.api"},
    excludeFilters={
         @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=com.company.common.jar1.Inteceptor1.class) ,
         @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=com.company.common.jar2.Inteceptor1.class)
    })
Run Code Online (Sandbox Code Playgroud)