Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot Configuration skip registration on multiple @Profile

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";
    ...
}
like image 604
gtiwari333 Avatar asked Feb 07 '16 10:02

gtiwari333


3 Answers

@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 { 
like image 159
Cyril Avatar answered Sep 24 '22 06:09

Cyril


Starting with Spring 5.1 you can use expressions in @Profile annotation. Read more in the @Profile documentation. Example:

@Configuration
@Profile({ "!console & !dev" }) 
public class MyConfigurationB {
    static{
        System.out.println("MyConfigurationB registering...");
    }
}
like image 27
xyz Avatar answered Sep 24 '22 06:09

xyz


With newer versions of Spring, the acceptsProfiles method which accepts strings has been deprecated.

To do the equivalent work as in Cyril's question, you would need to leverage the new method parameter. This newer format also gives you the flexibility to author profile expressions which are more powerful than what was in place prior, thus eliminating the need to negate the entire acceptsProfiles expression itself.

public class NotConsoleAndDevCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return environment.acceptsProfiles(Profiles.of("!console & !dev"));
    }
}
like image 27
Makoto Avatar answered Sep 23 '22 06:09

Makoto