Spring中@Conditional和Condition接口的运行原理

// @Condition条件计算器
class ConditionEvaluator {
    // 计算的上下文
    private final ConditionContextImpl context = new ConditionContextImpl(registry, environment, resourceLoader);

    // 校验是否需要跳过,未指定分阶段处理,也就是那个阶段都需要处理,调用@Conditon接口
    public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
        return shouldSkip(metadata, null);
    }

    /**
     * 根据@Conditional注解决定是否跳过某项
     *
     * @param metadata 注解的元信息
     * @param phase    调用的阶段,在指定的阶段才会调用Condition接口,如果不在当前指定的阶段,则不会调用Condition接口
     * @return true:当前类需要被跳过,不会被加载
     */
    public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
        // 如果没有注解信息,或者不存在Conditional注解,不处理,放行
        if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
            return false;
        }
        // 如果未指定在某个阶段处理
        if (phase == null) {
            // 判断元数据类型是不是注解的类型,并且是配置类
            // candidateIndicators.add(Component.class.getName());
            // candidateIndicators.add(ComponentScan.class.getName());
            // candidateIndicators.add(Import.class.getName());
            // candidateIndicators.add(ImportResource.class.getName());
            if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
                // 递归调用,传递当前阶段是处理一个配置类
                return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
            }
            // 如果是其他类型,那处理的阶段当做是注册一个Bean来处理
            return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
        }

        // 获取@Condition注解的处理类信息
        List<Condition> conditions = new ArrayList<>();
        // 获取注解上所有Condition接口实现类的全类名
        for (String[] conditionClasses : getConditionClasses(metadata)) {
            // 遍历所有全类名
            for (String conditionClass : conditionClasses) {
                // 使用类加载器加载该类,并且实例化
                Condition condition = getCondition(conditionClass, this.context.getClassLoader());
                // 保存处理类
                conditions.add(condition);
            }
        }
        // 对condition进行排序
        AnnotationAwareOrderComparator.sort(conditions);
        // 遍历所有的处理类
        for (Condition condition : conditions) {
            // 处理的阶段
            ConfigurationPhase requiredPhase = null;
            // 如果Conditionl类型是配置类ConfigurationCondition类型
            // 获取ConfigurationCondition提供的自定义阶段
            if (condition instanceof ConfigurationCondition) {
                requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
            }
            // 如果不是ConfigurationCondition类型,或者ConfigurationCondition没有指定处理的阶段,再或者给定的阶段和处理的阶段一致的情况下
            // 再调用Condition.matches方法,对当前类进行判断
            // 1. 如果是ConfigurationCondition类型,但是它未提供阶段的值,这个时候,表示无论在那个阶段都会处理,所以直接调用condition接口进行最终判断
            // 2. 如果不是ConfigurationCondition类型,那就是普通的Condition类型,这个时候也是直接调用condition接口进行最终判断
            // 3. 是ConfigurationCondition类型,并且ConfigurationCondition指定要处理的阶段和实际处理的阶段一致,这个时候才会处理,所以才需要调用condition接口进行最终判断
            // 4. 是ConfigurationCondition类型,但是指定的处理阶段和正在处理的阶段不一致,这个时候就没有必要处理了,也不会调用condition接口
            if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
                return true;
            }
        }
        // 处理完上面这些接口,最终确定是否需要被跳过
        return false;
    }

    /**
     * 获取注解上的类
     */
    private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
        // 找到该类上的Conditional注解信息
        MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
        // 获取注解的value属性
        Object values = (attributes != null ? attributes.get("value") : null);
        // 返回类的名称集合
        return (List<String[]>) (values != null ? values : Collections.emptyList());
    }

    private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) {
        // 使用类加载加加载该类
        Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);
        // 实例化该类
        return (Condition) BeanUtils.instantiateClass(conditionClass);
    }

}

// 将@Bean解析成BeanDefinition的类
class ConfigurationClassBeanDefinitionReader {
    // 处理@Bean方法
    private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        // 使用条件计算器计算当前配置类是否需要被跳过,指定当前处理的阶段是注册某个Bean的阶段
        if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
            // 如果需要被跳过,保存当前方法的@Bean不会被加载
            configClass.skippedBeanMethods.add(methodName);
            return;
        }
    }

    // 处理配置类的Class
    private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        // 使用跟踪类型的计算器,它相比普通的ConditionEvaluator类说,就是多了一个处理@Import类的校验规则,并且缓存了哪些类被忽略了
        // 内部还是调用普通ConditionEvaluator的实现
        if (trackedConditionEvaluator.shouldSkip(configClass) {
            // 获取当前配置类是不是缓存了标记被跳过
            Boolean skip = this.skipped.get(configClass);
            // 如果没有被标记
            if (skip == null) {
                // 判断当前配置类是不是导入的
                if (configClass.isImported()) {
                    boolean allSkipped = true;
                    // 获取导入当前类的所有配置类
                    for (ConfigurationClass importedBy : configClass.getImportedBy()) {
                        // 递归校验,校验导入当前类的配置类是否需要被跳过
                        // 意思就是有N个类导入当前类,只有所有的类的都被跳过,则当前被导入的类也要被跳过
                        // 因为导入当前类的所有类都不符合条件,所以当前类也没办法成为Bean
                        // 但是只要有一个导入的Bean是不需要被跳过,则当前配置类就有用
                        if (!shouldSkip(importedBy)) {
                            // 如果有一个不需要被跳过,标识不是所有的都需要被跳过
                            allSkipped = false;
                            break;
                        }
                    }
                    // 如果被导入当前类的所有配置类都被跳过了,那么当前配置类也会被跳过
                    if (allSkipped) {
                        skip = true;
                    }
                }
                // 如果上面没有标记当前类需要被跳过
                // 那么再次使用Condition注解计算器计算当前配置类是否需要被跳过
                if (skip == null) {
                    // 给定处理的阶段为注册Bean的阶段
                    skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);
                }
                // 缓存当前配置类是否需要被跳过
                this.skipped.put(configClass, skip);
            }
            return skip;
        }){
            // 如果需要被跳过
            // 获取Bean名称
            String beanName = configClass.getBeanName();
            // 如果已经保存了该bean的BeanDefinition,删除
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            // 再删除Import的关系
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }
    }

}

// 解析所有配置类信息的解析器
class ConfigurationClassParser {
    // 处理整个配置类
    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        // 使用条件计算器计算当前配置类是否需要被跳过,指定当前处理的阶段是解析配置类的阶段
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }
    }

    // 处理配置类的各个阶段的Bean
    protected void doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) {
        // 处理配置类的ComponentScans
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        // 如果不存在注解,或者
        // 使用条件计算器计算当前配置类是否需要被跳过,指定当前处理的阶段是注册Bean的阶段
        if (componentScans.isEmpty() || this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            return;
        }
    }

}
// 包扫描器
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    // 判断当前类是不是一个可用的Bean
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 使用排除的过滤器校验
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return false;
            }
        }
        // 使用包含的过滤器校验
        for (TypeFilter tf : this.includeFilters) {
            // 如果包含了该类,才需要校验Condition
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                // 判断@Condition是否符合条件
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

    // Condition条件匹配
    private boolean isConditionMatch(MetadataReader metadataReader) {
        // 如果没有条件计算器,创建一个
        if (this.conditionEvaluator == null) {
            this.conditionEvaluator = new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
        }
        // 使用条件计算器校验
        return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值