Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I negate (!) a collection of spring profiles?

Is it possible to configure a bean in such a way that it wont be used by a group of profiles? Currently I can do this (I believe):

@Profile("!dev, !qa, !local") 

Is there a neater notation to achieve this? Let's assume I have lots of profiles. Also, if I have a Mock and concrete implementation of some service (or whatever), Can I just annotate one of them, and assume the other will be used in all other cases? In other words, is this, for example, necessary:

@Profile("dev, prof1, prof2") public class MockImp implements MyInterface {...}  @Profile("!dev, !prof1, !prof2") //assume for argument sake that there are many other profiles public class RealImp implements MyInterface {...} 

Could I just annotate one of them, and stick a @Primary annotation on the other instead?

In essence I want this:

@Profile("!(dev, prof1, prof2)") 

Thanks in advance!

like image 371
HellishHeat Avatar asked Apr 02 '17 13:04

HellishHeat


People also ask

How do you exclude beans in spring?

You can exclude a bean from autowiring in Spring framework per-bean basis. If you are using Spring XML configuration then you can exclude a bean from autowiring by setting the autowire-candidate attribute of the <bean/> element to false.

Which of these are valid usages of spring profiles?

Spring @Profile allow developers to register beans by condition. For example, register beans based on what operating system (Windows, *nix) your application is running, or load a database properties file based on the application running in development, test, staging or production environment.

How do I add multiple accounts to spring boot?

The solution would be to create more property files and add the "profile" name as the suffix and configure Spring Boot to pick the appropriate properties based on the profile. Then, we need to create three application. properties : application-dev.


2 Answers

Since Spring 5.1 (incorporated in Spring Boot 2.1) it is possible to use a profile expression inside profile string annotation (see the description in Profile.of(..) for details).

So to exclude your bean from certain profiles you can use an expression like this:

@Profile("!dev & !prof1 & !prof2") 

Other logical operators can be used as well, for example:

@Profile("test | local") 
like image 125
Pascal Gafner Avatar answered Oct 12 '22 11:10

Pascal Gafner


Short answer is: You can't in versions of Spring prior to Spring 5.1 (i.e. versions of Spring Boot prior to 2.1).

But there is a neat workarounds that exists thanks to the @Conditional annotation.

Create Condition matchers:

public static abstract class ProfileCondition extends SpringBootCondition {     @Override     public ConditionOutcome getMatchOutcome(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {         if (matchProfiles(conditionContext.getEnvironment())) {             return ConditionOutcome.match("A local profile has been found.");         }         return ConditionOutcome.noMatch("No local profiles found.");     }      protected static abstract boolean matchProfiles(final Environment environment); }  public class DevProfileCondition extends ProfileCondition {    protected boolean matchProfiles(final Environment environment) {             return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {             return prof.equals("dev") || prof.equals("prof1") || prof.equals("prof2");         });     } }  public static class ProdProfileCondition extends ProfileCondition {    protected boolean matchProfiles(final Environment environment) {             return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {             return (!prof.equals("dev") && !prof.equals("prof1") && !prof.equals("prof2"));         });     } } 

Use it

@Conditional(value = {DevProfileCondition.class}) public class MockImpl implements MyInterface {...}  @Conditional(value = {ProdProfileCondition.class}) public class RealImp implements MyInterface {...} 

However, this aproach requires Springboot.

like image 29
Anthony Raymond Avatar answered Oct 12 '22 10:10

Anthony Raymond