Spring Boot Configuration skip registration on multiple @Profile

gtiwari333 picture gtiwari333 · Feb 7, 2016 · Viewed 15.5k times · Source

I've a Spring Boot application with different Profile setup : dev, prod, qc, console etc.

The two configuration classes are setup as follows. MyConfigurationA should be registered for all profiles except console. MyConfigurationB should be registered except for console and dev.

When I run the application with profile console, the MyConfigurationA doesn't get registered - which is fine. But MyConfigurationB gets registered - which I do not want. I've setup the @Profile annotation as follows to not register the MyConfigurationB for profile console and dev .

But the MyConfigurationB is getting registered when I run the application with profile console.

@Profile({ "!" + Constants.PROFILE_CONSOLE ,  "!" + Constants.PROFILE_DEVELOPMENT })

The documentation ( http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html) has an example of including one profile and excluding the other. In my example I'm excluding both as @Profile({"!p1", "!p2"}):

@Profile({"p1", "!p2"}), registration will occur if profile 'p1' is active OR if profile 'p2' is not active.

My question is : How can we skip registration of the configurations of both profiles? @Profile({"!p1", "!p2"}) is doing OR operation. We need AND operation here.


The code :

@Configuration
@Profile({ "!" + Constants.PROFILE_CONSOLE  })
public class MyConfigurationA {
    static{
        System.out.println("MyConfigurationA registering...");
    }
}

@Configuration
@Profile({ "!" + Constants.PROFILE_CONSOLE ,  "!" + Constants.PROFILE_DEVELOPMENT }) // doesn't exclude both, its OR condition
public class MyConfigurationB {
    static{
        System.out.println("MyConfigurationB registering...");
    }
}

public final class Constants {
    public static final String PROFILE_DEVELOPMENT = "dev";
    public static final String PROFILE_CONSOLE = "console";
    ...
}

Answer

Cyril picture Cyril · Feb 7, 2016

@Profile({"!console", "!dev"}) means (NOT console) OR (NOT dev) which is true if you run your app with the profile 'console'.
To solve this you can create a custom Condition:

public class NotConsoleAndDevCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return !environment.acceptsProfiles("console", "dev");
    }
}

And apply the condition via the @Conditional annotation to the Configuration:

@Conditional(NotConsoleAndDevCondition.class)
public class MyConfigurationB {