ConfigurationClassParser 是如何工作的 ?

简介

Spring的工具类 ConfigurationClassParser 用于分析一个 @Configuration 注解的类,产生一组ConfigurationClass对象。其分析过程主要是递归分析注解中隐含的@Import,找出其中所有的配置类,然后返回这组配置类。

这个工具类自身的逻辑并不会注册Bean定义,但是它用到了另外一个工具ComponentScanAnnotationParser在执行时会做Bean定义注册。

一般情况下一个@Configuration注解的类只会产生一个ConfigurationClass对象,但是因为@Configuration注解的类可能会使用另外一个注解@Import引入其他配置类,所以总的来看,ConfigurationClassParser分析一个 @Configuration注解的类,可能产生任意多个ConfigurationClass对象。

这个工具类分离了两个不同点关注点 :

  • @Configuration注解的类的结构分析

  • 注册BeanDefinition对象

主要功能分析

公开方法 parse() 外部调用入口

/**
     * 总体工作流程 :
     *  1. 外部提供参数 configCandidates , 是一组需要被分析的候选配置类 ;
     *  2. 调用该类的 parse() 方法, parse() 方法针对每个候选配置类,递归查找其注解@Import,
     *     以及注解的注解中的@Import,然后处理这些@Import,每个@Import可能对应一个ImportSelector,
     *     ImportBeanDefinitionRegistrar,或者是另外一个@Configuration注解的配置类,parse()会
     *     递归处理这些进一步的导入,直到所有所有的这些配置类都被发现,这些发现的每个ConfigurationClass,
     *     会被记录到 configurationClasses;
     *  3. 外部通过调用该类的方法 getConfigurationClasses() 获得分析过程中保存在 configurationClasses
     *     中的配置类;
     * @参数 configCandidates : 外部指定需要被分析的一组候选配置类
     **/
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 这里根据Bean定义的不同类型走不同的分支,但是最终都会调用到方法
                //  processConfigurationClass(ConfigurationClass configClass)
                if (bd instanceof AnnotatedBeanDefinition) {
                    // bd 是一个 AnnotatedBeanDefinition
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    // bd 是一个 AbstractBeanDefinition,并且指定 beanClass 属性
                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                }
                else {
                    // 其他情况
                    parse(bd.getBeanClassName(), holder.getBeanName());
                }
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
            }
        }

        // 执行找到的 DeferredImportSelector 
        processDeferredImportSelectors();
    }

保护方法 processConfigurationClass()分析一个配置类

私有方法 processDeferredImportSelectors() 处理需要延迟处理的ImportSelector

私有方法 doProcessConfigurationClass()对一个配置类执行处理和构建的主逻辑

私有方法 processImports()处理配置类上搜集到的@Import注解

Last updated

Was this helpful?