Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Profile - How to include AND condition for adding 2 profiles?

I don't want a specific bean to be loaded if either the active profile is test or local. However when I set the below , spring seems to be treating is as "or" and the method gets executed both when active profile is test or local. However if remove say local and keep test , then the bean is not created when the profile is test.

@Profile({"!test","!local"})
like image 377
Punter Vicky Avatar asked May 04 '18 19:05

Punter Vicky


People also ask

Can you use @component together with profile?

Yes, @Profile annotation can be used together with @Component on top of the class representing spring bean.

Can we use multiple profiles in Spring Boot?

profiles. active is a standard property that Spring Boot will pick up automatically to activate a profile. Pass the profile name to this property value to activate that profile. If we want to activate multiple profiles then we can pass comma-separated names of those profiles.

How many profiles can be defined for a spring application?

In the following application, we have three profiles (local, dev, prod) and two profile-specific property files. We use the spring. profiles. active to set active profiles and SpringApplicationBuilder's profiles method to add new active profiles.


2 Answers

Since Spring 5.1 (incorporated in Spring Boot 2.1) it is possible to use a profile expression inside profile string annotation. So:

In Spring 5.1 (Spring Boot 2.1) and above it is as easy as:

@Component
@Profile("!test & !local")
public class MyComponent {}

Spring 4.x and 5.0.x:

There are many approaches for this Spring versions, each one of them has its pro's and con's. When there aren't many combinations to cover I personally like the approach of using @Conditional like @Stanislav answered in a similar question. I post the solution here for the convenience of the reader:

Your Spring Bean:

@Component
@Conditional(value = { NotTestNorLocalProfiles.class })
public class MyComponent {}

NotTestNorLocalProfiles implementation:

public class NotTestNorLocalProfiles implements Condition {
    @Override
    public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
        return !context.getEnvironment().acceptsProfiles("test")
                    && !context.getEnvironment().acceptsProfiles("local");
    }
}

Other approaches can be found in this similar questions:

How to conditionally declare Bean when multiple profiles are not active?

Spring: How to do AND in Profiles?

like image 124
f-CJ Avatar answered Sep 28 '22 08:09

f-CJ


When using Spring Boot 1.X, you can update the System Property with an additional profile name and handle all the boolean logic before your SpringApplication.run. If it qualifies, you would append the profile name to the active profiles. If it doesn't, you would not change anything.

This is a very basic check but you can add more rigorous profile validation, such as null check and actually splitting the profiles list.

    String profile = System.getProperty("spring.profiles.active");
    if(!profile.contains("test") && !profile.contains("local")) {
        System.setProperty("spring.profiles.active", profile + ",notdev");
    }

If you are using Spring Boot 2.0, you can use addAdditionalProfiles to add the profile (don't have a SB2 app so I can't test this but I assume it just adds it to the System properties list).

    String profile = System.getProperty("spring.profiles.active");
    if(!profile.contains("test") && !profile.contains("local")) {
        SpringApplication.addAdditionalProfiles("notdev");
    }

Then your annotation can be:

@Profile({"notdev"})
like image 41
Compass Avatar answered Sep 28 '22 07:09

Compass