Allow Spring to have multiple WebMvcConfigurer implementations in different jars

user1884155 :

When using Spring Web, in this case for rest endpoints & using Spring Boot 2, I can configure interceptors for my app using by implementing the WebMvcConfigurer interface:

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

I added this interceptor to most of my apps in an automatic fashion by doing the following:

  1. Create a "common-jar", and put the above interface under package
    com.company.api.
  2. In every app, add the package com.company.api to the api scan.

This common package also contains the Interceptor and utility classes to make this interceptor work, so in effect, adding this common-jar would automatically add he interceptor to all operations in the app, which is a similar concept as to what Spring itself does: adding dependencies changes the default configuration of Spring.

The problem I'm facing now is this approach cannot be extended to a second interceptor in a second jar, because I already used the WebMvcConfigurer implementation. and I cannot have two.

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?

Currently, the approach I took is duplicating the WebMvcConfigurer interface in every app that requires it. I feel sad when something changes, and I have to change the same snippet of code in every single app.

Ken Chan :

If I understand your question correctly , basically you want to define some common Interceptors in multiple JARs such that an application can activate these Interceptors by simply including these JARs into their app ?

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 ?

Actually , Spring has already implement this feature. When there are multiple WebMvcConfigurer beans , Spring simply loop them one by one and calls their configuration methods. So the end-result is that InterceptorRegistry will contain all interceptors.

If the client application need to activate certain WebMvcConfigurer only, it can simply exclude those JARs containing the WebMvcConfigurer that they don't want.

To take this idea further which allow the application to control which Interceptors to activate down to interceptor level , you could even do the following in each common 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/**");
        }
    }
}

In the client application , use includeFilters / excludeFilters in @ComponentScan to customise which to interceptors to include. For example, to disable certain Interceptors, you could do :

@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)
    })

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=329342&siteId=1