美文网首页
spring @Conditional 与 @Profile

spring @Conditional 与 @Profile

作者: lj72808up | 来源:发表于2021-06-01 14:08 被阅读0次
    1. @Profile@Conditional
      在 Spring3.1 的版本,为了满足不同环境注册不同的 Bean ,引入了 @Profile 注解。例如:

      @Configuration
      public class DataSourceConfiguration {
      
          @Bean
          @Profile("DEV")
          public DataSource devDataSource() {
              // ... 单机 MySQL
          }
      
          @Bean
          @Profile("PROD")
          public DataSource prodDataSource() {
              // ... 集群 MySQL
          }
          
      }
      
      • 测试环境下,我们注册单机 MySQL 的 DataSource Bean 。
      • 生产环境下,我们注册集群 MySQL 的 DataSource Bean 。
        org.springframework.context.annotation.@Profile ,代码如下:
      // Profile.java
      
      @Conditional(ProfileCondition.class)
      public @interface Profile {
      
       /**
        * The set of profiles for which the annotated component should be registered.
        */
       String[] value();
      
      }
      
    2. @Conditional 注解

      • @Conditional 利用 Condition 接口声明的规则, 返回是否 match
        比如 @Profile 的定义上, 配合使用了 @Conditional(ProfileCondition.class)
      • Condition 接口
        只有一个方法, 返回是否匹配
        public interface Condition {
            boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
        }
        
    3. spring 对 Condition 接口的扩展 - ProfileCondition

      • @Profile 注解利用 ProfileCondition 返回是否匹配.
        获取 @Profile 的 value 属性,和 environment 是否有匹配的。如果有,则表示匹配。
        // Conditional.java
        
        @Conditional(ProfileCondition.class)
        public @interface Profile { ... }
        
        // ProfileCondition.java
        
        class ProfileCondition implements Condition {
            @Override
            public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
                // 获得 @Profile 注解的属性
                MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
                // 如果非空,进行判断
                if (attrs != null) {
                    // 遍历所有 @Profile 的 value 属性
                    for (Object value : attrs.get("value")) {
                        // 判断 environment 有符合的 Profile ,则返回 true ,表示匹配
                        if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
                            return true;
                        }
                    }
                    // 如果没有,则返回 false
                    return false;
                }
                // 如果为空,就表示满足条件
                return true;
            }      
        }
        
    4. spring boot 对 Condition 接口的扩展 - SpringBootCondition

      • SpringBootCondition 作为基类, 是一个抽象类. 把 match 结果封装成了 ConditionOutcome
        public abstract class SpringBootCondition implements Condition {
        
            private final Log logger = LogFactory.getLog(getClass());
        
            @Override
            public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
                // <1> 获得注解的是方法名还是类名
                String classOrMethodName = getClassOrMethodName(metadata);
                try {
                    // <2> 条件匹配结果 ConditionOutcome ( getMatchOutcome()是核心方法 ) 
                    ConditionOutcome outcome = getMatchOutcome(context, metadata);
                    logOutcome(classOrMethodName, outcome);
                    recordEvaluation(context, classOrMethodName, outcome);
                    // <3> 返回是否 match
                    return outcome.isMatch();
                }
                catch (NoClassDefFoundError ex) { ... }
                catch (RuntimeException ex) { ... }
            }
        }
        
    5. spring boot 基于基类 SpringBootCondition 实现了大量 Condition 子类.

      • OnPropertyCondition 为例
        // ConditionalOnProperty
        
        @Conditional(OnPropertyCondition.class)
        public @interface ConditionalOnProperty { ...}  
        
      • 使用方法
        通过其两个属性 name 以及 havingValue 来实现的,其中 name 用来从 application.properties 中读取某个属性值。
        如果该值为空,则返回false;
        如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。
        如果返回值为false,则该configuration不生效;为true则生效。
        @Configuration
        //在application.properties配置"mf.assert",对应的值为true
        @ConditionalOnProperty(prefix="mf",name = "assert", havingValue = "true")
        public class AssertConfig {
            @Autowired
            private HelloServiceProperties helloServiceProperties;
            @Bean
            public HelloService helloService(){
                HelloService helloService = new HelloService();
                helloService.setMsg(helloServiceProperties.getMsg());
                return helloService;
            }
        }
        

    相关文章

      网友评论

          本文标题:spring @Conditional 与 @Profile

          本文链接:https://www.haomeiwen.com/subject/jmvwsltx.html