javaspringspring-cloudservice-discovery

How to disable CompositeDiscoveryClient and SimpleDiscoveryClient in service discovery library


We've written an in-house service discovery (SD) client based on the spring-cloud-commons SPI, meaning it provides implementations for interfaces ServiceRegistry and DiscoveryClient and some other Spring-provided abstractions.

Apps that use our library merely add it to their pom file, and it autowires the DiscoveryClient with its own implementation, InHouseDiscoveryClient

<dependency>
   <groupId>blah.blah<groupId>
   <artifactId>inhouse-service-discovery-client<artifactId>
<dependency>

However, rather than referring to InHouseDiscoveryClient in code, it's best practices to use the interface DiscoveryClient as shown below

# Good 
@Autowired
DiscoveryClient client;

# Bad (binds app to a particular SD implementation)
@Autowired
InHouseDiscoveryClient client;

As such, we are required to add spring-cloud-commons to the project.

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
    </dependency>

This is where the issue starts. The commons library actually autowires two additional implementations of DiscoveryClient - the SimpleDiscoveryClient and the CompositeDiscoveryClient.

This makes for an odd user experience for our clients. Instead of simply having InHouseDiscoveryClient, users find themselves with these additional beans.

Is it possible to prevent spring-cloud-commons's DiscoveryClient implementations from autowiring? And if so, can this be done in our library rather than in the end-user's applications?


Solution

  • I ended up extended AutoConfigurationImportFilter in my library to remove the autowired beans from cloud-commons. I also removed it's health indicator, but we had a very particular reason to do so - most probably would rather keep it.

    my.package
    
    public class StratusDiscoveryExclusionFilter implements AutoConfigurationImportFilter {
    
    private static final Set<String> SHOULD_SKIP = new HashSet<>(
            Arrays.asList(
                    // DiscoveryClient Beans
                    "org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration",
                    "org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration",
                    // Health indicators
                    "org.springframework.cloud.client.CommonsClientAutoConfiguration")
    );
    
    /**
     * For each class name, provide an assocated boolean array indicated whether or not to include
     */
    @Override
    public boolean[] match(String[] classNames, AutoConfigurationMetadata metadata) {
        boolean[] matches = new boolean[classNames.length];
    
        for (int i = 0; i < classNames.length; i++) {
            matches[i] = !SHOULD_SKIP.contains(classNames[i]);
        }
        return matches;
     }
    }
    

    I think add a reference to this in my library's spring.factories file

    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=my.package.MyExclusionFilter