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

Allow Spring to have multiple WebMvcConfigurer implementations in different jars

当使用 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/**");
    }
}

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

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

这个通用包还包含拦截器和实用程序 类 让这个拦截器工作,所以实际上,添加这个通用 jar 会自动将拦截器添加到应用程序中的所有操作,这是一个类似的关于 Spring 本身做什么的概念:添加依赖项会更改 Spring.

的默认配置

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

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

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

如果我对你的问题理解正确的话,你不想在每个应用程序中实现 WebMvcConfigurer 的所有方法。您只想添加相关的拦截器并完成它。

我的方法是通过在 Common 模块中实现 WebMvcConfigurer 来创建 AbstractWebMvcConfigurerImpl。只留下 addInterceptors() 抽象并实现其他方法。然后,您可以在每个 Spring 引导项目中扩展该抽象实现,并根据需要覆盖 addInterceptors() 方法。

此外,您可以在 Spring 项目中实现任意数量的 WebMvcConfigurer。所以,如果你需要在 Common 模块中定义一些通用的拦截器,你也可以在通用模块中扩展 AbstractWebMvcConfigurerImpl

请注意,您对 AbstractWebMvcConfigurerImpl 的所有实现都应使用 @Configuration

进行注释

如果我对你的问题的理解正确,那么基本上你想在多个 JAR 中定义一些常见的 Interceptors,这样应用程序就可以通过简单地将这些 JAR 包含到他们的应用程序中来激活这些 Interceptors

I was thinking about maybe using some kind of composite-configurer pattern where we loop over every configurer, collect all interceptors, and then add them once, but unfortunately Spring doesn't allow this. What are my options?

Well, if implementation A returns a registry with only interceptor A, and implementation B returns a registry with only interceptor B, would spring combine both registries into one super registry containing both A and B, or would it just pick one, or would it throw an error that there was no unique bean definition ?

实际上,Spring 已经实现了 this feature. When there are multiple WebMvcConfigurer beans , Spring simply loop them one by one 并调用了它们的配置方法。所以 end-result 是 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/**");
        }
    }
}

在客户端应用程序中,使用 @ComponentScan 中的 includeFilters / excludeFilters 自定义要包含的拦截器。例如,要禁用某些 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)
    })