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";
...
}
@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 {
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...");
}
}
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"));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With