bladekp
bladekp

Reputation: 1657

How to exclude package in given runtime profile in Spring Boot application

In my application I have two profiles dev and prod, I can exclude beans using org.springframework.context.annotation.Profile annotation:

package com.example.prod;

@Service
@Profile("prod")
public class MyService implements MyBaseService {}

The problem is, I have several beans which are annotated in such way, all of them are in same package com.example.prod. Similar structure exists for dev profile (com.example.dev package), and may in future I will have some additional profiles. Is there possibility to exclude whole package at once? I tried to play with org.springframework.context.annotation.ComponentScan, but I was unable to add exclude filters depends on actual profile, I wonder if there is easy way to solve my problem.

Upvotes: 2

Views: 6263

Answers (1)

Ken Chan
Ken Chan

Reputation: 90527

You can implement a custom TypeFilter to disable ComponentScan for certain packages based on the active profile . A kick-start example is :

(1) Implement the Filter. For demo purpose , I hard codes that if the active profile is dev , it will exclude the package configured by devExcludePackage property. For prod profile , it will exclude the package configured by prodExcludePackage :

public class ExcludePackageTypeFilter implements TypeFilter , EnvironmentAware  {

    private Environment env;

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {

        boolean match = false;
        for (String activeProfile : env.getActiveProfiles()) {
            if (activeProfile.equals("dev")) {
                match = isClassInPackage(metadataReader.getClassMetadata(), env.getProperty("devExcludePackage"));
            } else if (activeProfile.equals("prod")) {
                match = isClassInPackage(metadataReader.getClassMetadata(), env.getProperty("prodExcludePackage"));
            }
        }
        return match;
    }

    private boolean isClassInPackage(ClassMetadata classMetadata, String pacakage) {
        return classMetadata.getClassName().startsWith(pacakage);
    }


    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }
} 

(2) Configure application.properties to define which packages to exclude for different profiles.

devExcludePackage  = com.example.prod
prodExcludePackage = com.example.dev

(3) Apply this filter to @ComponentScan :

@SpringBootApplication
@ComponentScan(excludeFilters = @ComponentScan.Filter(
                type = FilterType.CUSTOM, classes = { ExcludePackageTypeFilter.class }))
public class Application {


}

Upvotes: 5

Related Questions