Back to Javatutorial

ConfigurationClassPostProcessor(四):处理@Conditional注解

docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(四):处理@Conditional注解.md

1.0.08.9 KB
Original Source

ConfigurationClassPostProcessor ĵƪҪǷ spring @Conditional עĴ̡

5. spring δ @Conditional עģ

5.1 @Conditional Ĵ

ǰ ConfigurationClassParser#processConfigurationClass ʱôһУ

class ConfigurationClassParser {
    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        // жǷҪ @Conditional ע⣬жǷ
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), 
                ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }
        ...
    }
    ...
}

conditionEvaluator.shouldSkip(...) @Conditional עģĴ̣ٷʲô @Conditional ע⣺

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

    /**
     * 
     */
    Class<? extends Condition>[] value();

}

@Conditional עdz򵥣һԣֵ Class[]ұ ConditionCondition

public interface Condition {

    /**
     * ָƥ߼
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

Condition ӿڽһ matches ǿָƥ߼

conditionEvaluator.shouldSkip(...) Ĵ̣

class ConditionEvaluator {
    public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, 
            @Nullable ConfigurationPhase phase) {
        // Ƿ @Conditional
        if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
            return false;
        }
        // жϴ phase
        if (phase == null) {
            if (metadata instanceof AnnotationMetadata &&
                    ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
                return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
            }
            return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
        }

        // ʵ condition conditions 
        List<Condition> conditions = new ArrayList<>();
        // 1\. getConditionClasses(metadata)ȡ @Conditional ָж
        for (String[] conditionClasses : getConditionClasses(metadata)) {
            for (String conditionClass : conditionClasses) {
                // 2\. ʵõĻǷ䣩ͳһŵ conditions 
                Condition condition = getCondition(conditionClass, this.context.getClassLoader());
                conditions.add(condition);
            }
        }
        // 3\. õ condition ʵ
        AnnotationAwareOrderComparator.sort(conditions);
        // õ conditions
        for (Condition condition : conditions) {
            ConfigurationPhase requiredPhase = null;
            if (condition instanceof ConfigurationCondition) {
                requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
            }
            // 4\.  Condition#matches ж
            if ((requiredPhase == null || requiredPhase == phase) && 
                    !condition.matches(this.context, metadata)) {
                return true;
            }
        }

        return false;
    }

    ...
}

÷Ĵ£

  1. ȡ @Conditional ָж࣬ @Conditional value ֵ
  2. ʹ ʵ 1 õж࣬ 浽 conditionsǸ List У
  3. Ե 2 õ conditions
  4. 3 õ conditions Condition#matches ƥ䡣

@Conditional ĴǷdz򵥵ģʹʾ

5.2 @Conditional ʹʾ

ʾ 1ָʱŴ spring bean

ʵָܣָʱŽ spring bean Ĵʼ£

  1. ׼һ򵥵 bean:

    public class BeanObj {
    
    }
    
    
  2. ʵ Condition ӿڣﴦж߼

    public class MyCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String className = "java.lang.Object";
            try {
                // жǷ
                Class.forName(className);
                return true;
            } catch (ClassNotFoundException e) {
                return false;
            }
        }
    }
    
    

    matches(...) ָ className Ϊ java.lang.ObjectȻжǷڣжϷʽҲ ʮּ ʹ java ķƣClass.forName(...)಻ʱ׳ ClassNotFoundExceptionǿԲ쳣Ӷ֪ڲˡ

  3. ׼

    @ComponentScan
    public class BeanConfigs {
        @Bean
        @Conditional(MyCondition.class)
        public BeanObj beanObj() {
            return new BeanObj();
        }
    }
    
    

    Ƚϼ򵥣Ҫע beanObj() ϵ @Conditional ע⣬ָƥ MyConditionƥнеġ

public class Demo06Main {
    public static void main(String[] args) {
        ApplicationContext context 
                = new AnnotationConfigApplicationContext(BeanConfigs.class);
        try {
            Object obj = context.getBean("beanObj");
            System.out.println("beanObj ڣ");
        } catch (Exception e) {
            System.out.println("beanObj ڣ");
        }
    }
}

У£

beanObj ڣ

MyCondition#matches УжϵǵǰĿǷ java.lang.ObjectȻǴڵģ beanObj spring Уǻ className:

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 
        String className = "java.lang.Object111";
        ...
    }
}

Ȼjava.lang.Object111 DzڵǰĿеģУ£

beanObj ڣ

ʾ 2Ľʾ 1

ʾ 1 Уͨ MyCondition#matches ޸ className ı beanObj еĴĿзdzҪĴмأʵֶ MyCondition

A Ҫ A1 ĴжǷгʼ B Ҫ B1 ĴжǷгʼ C Ҫ C1 ĴжǷгʼ... ǷҪֱΪA``B``C ʵ ConditionڸԵ match(...) нж

ʵϣDzҪôͨ spring עķϹܡ

  1. ׼һ beanʾ 1

    public class BeanObj {
    
    }
    
    
  2. ׼ע @ConditionalForClassע @Conditional ĹܣƥΪ MyCondition``className ԾDZڵࣺ

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//  @Conditional ĹܣƥΪ MyCondition
@Conditional(MyCondition.class)
public @interface ConditionalForClass {

    /**
     * ָڵ
     */
    String className();

}

  1. ׼ MyConditionעʾIJڣclassName ڸ÷ж壬 @ConditionalForClass

    public class MyCondition implements Condition {
        /**
         * ﴦƥעʾ1е
         */
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // ȡ @ConditionalForClass עֵ
            Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(
                    ConditionalForClass.class.getName());
            // ȡclassNameֵ @ConditionalForClass  className 
            String className = (String)annotationAttributes.get("className");
            if(null == className || className.length() <= 0) {
                return true;
            }
            try {
                // жǷ
                Class.forName(className);
                return true;
            } catch (ClassNotFoundException e) {
                return false;
            }
        }
    }
    
    
  2. ׼࣬ʱעΪ @ConditionalForClass

    @ComponentScan
    public class BeanConfigs {
        @Bean
        /**
         *  @ConditionalForClass ָ
         */
        @ConditionalForClass(className = "java.lang.Object")
        public BeanObj beanObj() {
            return new BeanObj();
        }
    }
    
    
  3. ࣬ʾ 1

    public class Demo07Main {
    
        public static void main(String[] args) {
            ApplicationContext context 
                    = new AnnotationConfigApplicationContext(BeanConfigs.class);
            try {
                Object obj = context.getBean("beanObj");
                System.out.println("beanObj ڣ");
            } catch (Exception e) {
                System.out.println("beanObj ڣ");
            }
        }
    }
    
    

ͨԶע @ConditionalForClass ָ java.lang.Object ʱbeanObj Żᱻӵ spring УȻУ£

beanObj ڣ

@ConditionalForClass className ֵ

@ComponentScan
public class BeanConfigs {
    @Bean
    // ޸@ConditionalForClassclassNameֵ
    @ConditionalForClass(className = "java.lang.Object1111")
    public BeanObj beanObj() {
        return new BeanObj();
    }
}

@ConditionalForClass className ֵΪ java.lang.Object1111ȻಢڵǰĿУн£

beanObj ڣ

Ҳǵһ¡

ǻصڿͷ⣺磬 A Ҫ A1 ĴжǷгʼ B Ҫ B1 ĴжǷгʼ C Ҫ C1 ĴжǷгʼ... ǷҪֱΪA``B``C ʵ ConditionڸԵ match(...) нж

@ConditionalForClass עDzҪô鷳ֻҪڸԵ @Bean @ConditionalForClass ˣ

@Bean
@ConditionalForClass(className = "A1")
public A a() {
    return new A();
}

@Bean
@ConditionalForClass(className = "B1")
public B b() {
    return new B();
}

@Bean
@ConditionalForClass(className = "B1")
public C c() {
    return new C();
}

...

ע @ConditionalForClass ʵ֣springboot е @ConditionalOnClass ǰ˼·ʵֵġ

5.3 ܽ

Ҫ spring @Conditional ̣߼Ƚϼ򵥣յõ Condition#matches ƥģƥ Condition ʵָ

Ϊ˸õ˵ @Conditional ʹã׼ʹʾرʾ 2Ҫرᣬspringboot е @ConditionalOnClass ǻʾ 2 ˼·ʵֵģ⣬springboot еĶעҲǶ @Conditional չ


ԭӣhttps://my.oschina.net/funcy/blog/4873444 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע