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

前端 未结 5 1181
猫巷女王i
猫巷女王i 2020-11-30 03:22

In my Spring-Boot-App I want to conditionally declare a Bean, depending on (un)loaded spring-profiles.

The conditon:

Profile \"a\" NOT loaded  
AND           


        
相关标签:
5条回答
  • 2020-11-30 04:12

    Unfortunately I don't have a shorter solution for you, but if it is suitable in your case to create the same beans for each profile, you may consider the following approach.

    @Configuration
    public class MyBeanConfiguration {
    
       @Bean
       @Profile("a")
       public MyBean myBeanForA() {/*...*/}
    
       @Bean
       @Profile("b")
       public MyBean myBeanForB() {/*...*/}
    
       @Bean
       @ConditionalOnMissingBean(MyBean.class)
       public MyBean myBeanForOthers() {/*...*/}
    
    }
    
    0 讨论(0)
  • 2020-11-30 04:16

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

    In Spring 5.1.4 (Spring Boot 2.1.2) and above it is as easy as:

    @Component
    @Profile("!a & !b")
    public class MyComponent {}
    

    In 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 @Stanislav answer with the @Conditional annotation.

    Other approaches can be found in this similar questions:

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

    Spring: How to do AND in Profiles?

    0 讨论(0)
  • 2020-11-30 04:16

    I prefer this solution which is more verbose but still fine for two profiles only:

    @Profile("!a")
    @Configuration
    public class NoAConfig {
    
        @Profile("!b")
        @Configuration
        public static class NoBConfig {
            @Bean
            public MyBean myBean(){
                return new MyBean();
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 04:18

    If you have a single profile you could simply use a @Profile annotation with the not operator. It also accepts multiple profiles, but with the OR condition.

    So, the alternative solution is to use a custom Condition with the @Conditional annotation. Like so:

    public class SomeCustomCondition implements Condition {
      @Override
      public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    
        // Return true if NOT "a" AND NOT "b"
        return !context.getEnvironment().acceptsProfiles("a") 
                      && !context.getEnvironment().acceptsProfiles("b");
      }
    }
    

    And then annotate your method with it, like:

    @Bean
    @Conditional(SomeCustomCondition.class)
    public MyBean myBean(){/*...*/}
    
    0 讨论(0)
  • 2020-11-30 04:27

    A variant of @Stanislav answer which is a tiny bit more readable, for Spring versions up to 5.0.x / Spring Boot 2.0.x.

    public class SomeCustomCondition implements Condition {
      @Override
      public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
        final Environment environment = context.getEnvironment();
    
        // true if profile is NOT "a" AND NOT "b" AND NOT "c"
        return !environment.acceptsProfiles("a", "b", "c");
      }
    }
    

    For newer versions of Spring / Spring Boot, see the f-CJ answer.

    0 讨论(0)
提交回复
热议问题