10

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"})
Punter Vicky
  • 15,954
  • 56
  • 188
  • 315
  • Do you have to use annotations or can you use the Environment to fetch properties? – Compass May 04 '18 at 19:20
  • I have to use annotations. property is set in application.yml. – Punter Vicky May 04 '18 at 19:22
  • Possible duplicate of [Spring: How to do AND in Profiles?](https://stackoverflow.com/questions/27055072/spring-how-to-do-and-in-profiles) – Compass May 04 '18 at 19:27
  • Possible duplicate of [How to conditionally declare Bean when multiple profiles are not active?](https://stackoverflow.com/questions/35429168/how-to-conditionally-declare-bean-when-multiple-profiles-are-not-active) – Nick DeFazio May 04 '18 at 19:28
  • @Compass In my scenario , I need to use !Profile. I guess in the linked answer , NOT is not being used. – Punter Vicky May 04 '18 at 19:28
  • The only other method I can think of that doesn't get into weird Spring rewriting would be to check the profiles provided before start, and add additional profile specifically for this profile that handles this. – Compass May 04 '18 at 19:29
  • Are you using spring boot, and if so, 1 or 2? – Compass May 04 '18 at 19:40

3 Answers3

9

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?

f-CJ
  • 4,235
  • 2
  • 30
  • 28
3

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"})
Compass
  • 5,867
  • 4
  • 30
  • 42
1

Use @Profile({"Dummy"}).

You can replace "Dummy", if you want to use a valid profile name later.

Sundararaj Govindasamy
  • 8,180
  • 5
  • 44
  • 77
  • Thanks @Sundarrajan. But I want this to be executed for other profiles such as dev , qa or anything else that I might add in future. – Punter Vicky May 04 '18 at 19:32