• Spring refresh 方法之invokeBeanFactoryPostProcessors 方法解析


    • 三哥

    内容来自【自学星球】

    欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。

    想要了解更多,欢迎访问👉:自学星球

    --------------SSM系列源码文章及视频导航--------------

    创作不易,望三连支持!

    SSM源码解析视频

    👉点我

    Spring

    1. Spring 中注入 Bean 的各种骚操作做
    2. Spring 中Bean的生命周期及后置处理器使用
    3. Spring 中容器启动分析之refresh方法执行之前
    4. Spring refresh 方法分析之一
    5. Spring refresh 方法之二 invokeBeanFactoryPostProcessors 方法解析
    6. Spring refresh 方法分析之三
    7. Spring refresh 方法之四 finishBeanFactoryInitialization 分析
    8. Spring AOP源码分析一
    9. Spring AOP源码分析二
    10. Spring 事务源码分析

    SpringMVC

    1. SpringMVC 启动流程源码分析
    2. SpringMVC 请求流程源码分析

    MyBatis

    1. MyBatis 源码分析之 SqlSessionFactory 创建
    2. MyBatis 源码分析之 SqlSession 创建
    3. MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
    4. MyBatis 源码分析之 Select 语句执行(上)
    5. MyBatis 源码分析之 Select 语句执行(下)
    6. MyBatis 源码分析一二级缓存

    ---------------------【End】--------------------

    一、refresh 方法之 invokeBeanFactoryPostProcessors

    进入源码

    org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 重点在这个方法
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再次进入

    org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

    public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        // 优先执行 BeanDefinitionRegistryPostProcessors
        // 将已经执行的 postProcessBeanDefinitionRegistry  存储在 processedBeans 中,防止重复执行
        Set<String> processedBeans = new HashSet<>();
    
        // 判断 beanFactory 是否是 BeanDefinitionRegistry,是
        if (beanFactory instanceof BeanDefinitionRegistry) {
            // 类型强转
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            // 创建两个集合,分别存放不同的 BeanFactory 后置处理器
            List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
    
            // 首先处理参数传递过来的 BeanFactoryPostProcessor,遍历所有的BeanFactoryPostProcessors
            // 将 BeanDefinitionRegistryPostProcessor 和BeanFactoryPostProcessor  区分开
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    // BeanDefinitionRegistryPostProcessor 类型,先执行 postProcessBeanDefinitionRegistry 方法,在放入 registryProcessors 集合中
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    // beanFactoryPostProcessors 类型,存入 regularPostProcessors 集合中
                    regularPostProcessors.add(postProcessor);
                }
            }
    
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            // 用于保存本次要执行的 BeanDefinitionRegistryPostProcessor
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    
            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            // 调用所有实现 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor 实现类
            // 找到所有实现BeanDefinitionRegistryPostProcessor 接口的 bean 的beanName
            String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            // 遍历处理所有的符合规则的postProcessorNames
            for (String ppName : postProcessorNames) {
                // 检测是否实现PriorityOrdered接口
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    // 获取名字对应的bean实例,添加到currentRegistryProcessors中
                    // beanFactory.getBean中会进行相关相关bean的实例化工作
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //将要执行的BFPP名称添加到processedBeans中,避免后续重复执行
                    processedBeans.add(ppName);
                }
            }
            // 排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            // 添加registryProcessors,用于最后执行的postProcess方法
            registryProcessors.addAll(currentRegistryProcessors);
            // 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 执行完毕,清空currentRegistryProcessors集合
            currentRegistryProcessors.clear();
    
            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            // 调用所有实现 Ordered 接口的BeanDefinitionRegistryPostProcessor实现类
            // 找到所有实现BeanDefinitionRegistryPostProcessor 接口的bean的beanName
            // 此处需要重复查找的原因在于可能在上面执行的过程中会新增新的
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 检测是否实现Ordered接口,并且还未被执行过
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    // 获取名字对应的bean实例,添加到currentRegistryProcessors中
                    // beanFactory.getBean中会进行相关相关bean的实例化工作
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //将要执行的BFPP名称添加到processedBeans中,避免后续重复执行
                    processedBeans.add(ppName);
                }
            }
            // 排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            // 添加registryProcessors,用于最后执行的postProcess方法
            registryProcessors.addAll(currentRegistryProcessors);
            //遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            //执行完毕,清空currentRegistryProcessors集合
            currentRegistryProcessors.clear();
    
            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            // 最后执行其他的 BeanDefinitionRegistryPostProcessor 实现类
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    // 只有不包含的才执行, 执行完之后会添加进 processedBeans
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                // 排序
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                // 添加registryProcessors,用于最后执行的postProcess方法
                registryProcessors.addAll(currentRegistryProcessors);
                // 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                // 执行完毕,清空currentRegistryProcessors集合
                currentRegistryProcessors.clear();
            }
    
            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            // 调用所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory 方法
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            // 最后调用父类的入参BeanFactoryPostProcessor中普通BeanFactoryPostProcessor的postProcessBeanFactory 方法
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }
    
        else {
            // Invoke factory processors registered with the context instance.
            // 如果beanFactory不属于BeanDefinitionRegistry类型,直接执行postProcessBeanFactory方法
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }
    
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // 到此为止,入参beanFactoryProcessors和容器中所有的BeanDefinitionRegistryPostProcessor已经全部处理完成
        // 现在开始处理BeanFactoryPostProcessor
        // 这里可能存在一部分只实现了BeanFactoryPostProcessor,没有实现BeanDefinitionRegistryPostProcessor接口的类
    
        // 此处代码beanFactory.getBeanNamesForType在上面进行多次调用,但是传递参数不同,BeanDefinitionRegistryPostProcessor.class会注册实现BeanFactoryPostProcessor接口的类,但是BeanFactoryPostProcessor不会注册新的实现BeanFactoryPostProcessor接口的类
        String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    
        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        // 用于存放实现了priorityOrdered接口的beanName集合
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        // 用于存放实现了ordered接口的BeanFactoryProcessor的beanName
        List<String> orderedPostProcessorNames = new ArrayList<>();
        // 存放普通的BeanFactoryProcessor的beanName
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        // 遍历postProcessorNames,将三种不同集合区分开
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // 已经执行过的BeanFactoryPostProcessor不再执行
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // PriorityOrdered
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                // Ordered
                orderedPostProcessorNames.add(ppName);
            }
            else {
                // 普通的
                nonOrderedPostProcessorNames.add(ppName);
            }
        }
    
        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        // 对实现priorityOrdered接口的BeanFactoryPostProcessor进行排序
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        // 对实现priorityOrdered接口的BeanFactoryPostProcessor执行PostProcessorBeanFactory方法
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
        // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        // 创建实现 ordered 接口的 BeanFactoryPostProcessor 实现类集合
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : orderedPostProcessorNames) {
            // 获取名字对应的bean实例,添加到orderedPostProcessors中
            // beanFactory.getBean中会进行相关相关bean的实例化工作
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        // 对实现ordered接口的BeanFactoryPostProcessor进行排序
        sortPostProcessors(orderedPostProcessors, beanFactory);
        // 对实现ordered接口的BeanFactoryPostProcessor执行PostProcessorBeanFactory方法
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    
        // Finally, invoke all other BeanFactoryPostProcessors.
        // 创建存放BeanFactoryPostProcessor的集合对象,没有实现其他接口
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            // 获取名字对应的bean实例,添加到nonOrderedPostProcessors中
            // beanFactory.getBean中会进行相关相关bean的实例化工作
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        // 遍历nonOrderedPostProcessors, 执行postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    
        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        // 清除元数据缓存(mergedBeanDefinitions、allBeanNamesByType、singletonBeanNamesByType),
        // 因为后处理器可能已经修改了原始元数据,例如, 替换值中的占位符...
        beanFactory.clearMetadataCache();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199

    这个方法整体看下来非常长,但总的来说也就是围绕两个接口 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 进行处理,其中 BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor。

    在这里插入图片描述

    该方法一共操作了三种 Bean 对象:

    1. 入参 beanFactoryPostProcessors:这个值拿的是 AbstractApplicationContext 类的 beanFactoryPostProcessors 属性值,也就是在之前已经添加到 beanFactoryPostProcessors 中的 BeanFactoryPostProcessor
    2. 实现 BeanDefinitionRegistryPostProcessor.class 接口的 Bean:实现了 BeanDefinitionRegistryPostProcessor 接口,并且 Bean 定义已经存入了 beanFactory 中
    3. 实现 BeanFactoryPostProcessor.class 接口的 Bean:实现了 BeanFactoryPostProcessor接口,并且 Bean 定义已经存入了 beanFactory 中

    处理这三种 Bean 的流程也就是执行这些 Bean 中重写的 BeanFactoryPostProcessor 相关方法,那具体的执行顺序如下:

    1. 第一优先级:入参 beanFactoryPostProcessors 中的 BeanDefinitionRegistryPostProcessor, 调用 postProcessBeanDefinitionRegistry 方法
    2. 第二优先级:BeanDefinitionRegistryPostProcessor 接口实现类,并且实现了 PriorityOrdered 接口,调用 postProcessBeanDefinitionRegistry 方法
    3. 第三优先级:BeanDefinitionRegistryPostProcessor 接口实现类,并且实现了 Ordered 接口,调用 postProcessBeanDefinitionRegistry 方法
    4. 第四优先级:除去第二优先级和第三优先级,剩余的 BeanDefinitionRegistryPostProcessor 接口实现类,调用 postProcessBeanDefinitionRegistry 方法
    5. 第五优先级:所有 BeanDefinitionRegistryPostProcessor 接口实现类,调用 postProcessBeanFactory 方法
    6. 第六优先级:入参 beanFactoryPostProcessors 中的常规 BeanFactoryPostProcessor,调用 postProcessBeanFactory 方法
    7. 第七优先级:常规 BeanFactoryPostProcessor 接口实现类,并且实现了 PriorityOrdered 接口,调用 postProcessBeanFactory 方法
    8. 第八优先级:常规 BeanFactoryPostProcessor 接口实现类,并且实现了 Ordered 接口,调用 postProcessBeanFactory 方法
    9. 第九优先级:除去第七优先级和第八优先级,剩余的常规 BeanFactoryPostProcessor 接口的实现类,调用 postProcessBeanFactory 方法

    另外,在 invokeBeanFactoryPostProcessors 方法中涉及到了两个排序接口:PriorityOrdered 和 Ordered,其中 PriorityOrdered 继承了 Ordered,并且 PriorityOrdered 的优先级要高于 Ordered 这跟 BeanDefinitionRegistryPostProcessor 继承 BeanFactoryPostProcessor 有点类似。

    实现 Ordered 接口需要重写 getOrder 方法,返回一个用于排序的 order 值,order 值的范围为 Integer.MIN_VALUE ~ Integer.MAX_VALUE,order 值越小优先级越高,Integer.MIN_VALUE 拥有最高优先级,而 Integer.MAX_VALUE 则对应的拥有最低优先级。

    自此,invokeBeanFactoryPostProcessors 方法的执行流程我们分析完了,但是有一个悬念我们一直没有提:后置处理器的执行流程

    这里排除我们自己的后置处理器外,我必须要讲的一个就是 ConfigurationClassPostProcessor 后置处理器,它非常非常重要,在我源码调试阶段也只找到这一个非用户自定义的后置处理器及,系统默认的后置处理器。

    下面我们就来解开这个面纱。

    二 、ConfigurationClassPostProcessor

    前面提到,Spring 启动的时候容器中只有这一个系统默认的后置处理器,那它是在何时加入到容器中的呢!这是我们的一个关注点。

    其实如果是从头看我这笔记的,因该能在 10.3 节中找到答案。

    接下来我们看看这个类的结构关系图:

    在这里插入图片描述

    现在能明白它为什么是后置处理器、也能明白它为什么最先执行了吧!

    那分析 ConfigurationClassPostProcessor 方法的切入点在哪呢!

    两个切入口,分别对应不同的方法:

    1. org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors 方法,对应的是 ConfigurationClassPostProcessor 类的 postProcessBeanDefinitionRegistry 方法被执行
    2. org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法,对应的是 ConfigurationClassPostProcessor 类的 postProcessBeanFactory 方法被执行

    那,现在就明确了,先分析 postProcessBeanDefinitionRegistry 方法执行流程。

    三、ConfigurationClassPostProcessor 之 postProcessBeanDefinitionRegistry

    方法源码:

    org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 根据对应的registry对象生成hashcode值,此对象只会操作一次,如果之前处理过就抛出异常
        int registryId = System.identityHashCode(registry);
        if (this.registriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + registry);
        }
        // 将id添加到马上要处理的registry对象放到集合中
        this.registriesPostProcessed.add(registryId);
        // 处理配置类的bean的定义信息,重要重要重要
        processConfigBeanDefinitions(registry);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    进入 processConfigBeanDefinitions 方法源码

    org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        // 创建存放 BeanDefinitionHolder 的对象集合(配置类 Bean)
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        // 对当前registry就是DefaultListableBeanFactory,获取所有已经注册的BeanDefinition的baneName
        String[] candidateNames = registry.getBeanDefinitionNames();
    
        // 遍历,主要是筛选出我们的注解配置类
        for (String beanName : candidateNames) {
            // 获取指定名称的BeanDefinition对象
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            // 判断当前BeanDefinition是否是一个配置类,并为BeanDe设置属性为Lite或者Full,此处设置值是为了后续进行调用
            // 如果Configuration配置proxyBeanMethods代理为true则为full
            // 如果加了@Bean,@ComponentScan,@Component,@Import,@ImportResource注解,则是指为lite
            // 如果配置类被@Order注解标注,则设置BeanDefinition的order属性值
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                // 添加到对应的集合对象中去
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }
    
        // Return immediately if no @Configuration classes were found
        // 如果没有任何配置类则会直接返回
        if (configCandidates.isEmpty()) {
            return;
        }
    
        // Sort by previously determined @Order value, if applicable
        // 对configCandidates集合进行排序
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
        });
    
        // Detect any custom bean name generation strategy supplied through the enclosing application context
        // 判断当前类型是否是SingletonBeanRegistry类型,进行相关beanName生成器生成策略配置
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }
    
        // 环境对象为空则创建新环境对象
        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }
    
        // Parse each @Configuration class
        // 实例化ConfigurationClassParser类,并初始化相关参数,完成配置类的相关解析工作
        ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
        // 创建两个不重复的集合
        // 存放 BeanDefinitionHolder 数据(指定大小是为了避免扩容和内存浪费,放的是我们的配置类)
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        // 已解析的配置类集合
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            // 解析带有@Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean的BeanDefinition
            parser.parse(candidates);
            // 将解析完的Configuration配置类进行校验,1、配置类不能是final,2、@Bean修饰的方法必须可以重写以支持CGLIB
            parser.validate();
    
            // 获取所有的bean,包括扫描的bean对象,@Import导入的bean对象
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            // 清除掉已经解析处理过的配置类
            configClasses.removeAll(alreadyParsed);
    
            // Read the model and create bean definitions based on its content
            // 判断读取器是否为空,如果为空的话,就创建完全填充好的ConfigurationClass实例的读取器
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
            }
            // 核心方法,将完全填充好的ConfigurationClass实例转化为BeanDefinition注册入IOC容器
            this.reader.loadBeanDefinitions(configClasses);
            // 添加到已经处理的集合中
            alreadyParsed.addAll(configClasses);
    
            candidates.clear();
    
            // 这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
            // 实际上就是看配置类(例如AppConfig类会向BeanDefinitionMap中添加bean)
            // 如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length
            // 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析
            // 这里的AppConfig类向容器中添加的bean,实际上在parser.parse()这一步已经全部被解析了
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                Set<String> alreadyParsedClasses = new HashSet<>();
                for (ConfigurationClass configurationClass : alreadyParsed) {
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                }
                // 如果有未解析的类,则将其添加到candidates中,这样candidates不为空,就会进入到下一次的while的循环中
                for (String candidateName : newCandidateNames) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                            !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());
    
        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
        if (sbr != null) {
            if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }
        }
    
        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
            // Clear cache in externally provided MetadataReaderFactory; this is a no-op
            // for a shared cache since it'll be cleared by the ApplicationContext.
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135

    总结一下这个方法干了些啥:

    1. 拿到 BeanFactory 中所有注册的 Bean 定义名称
    2. 遍历根据 Bean 名称获取 Bean 定义并且判断是否为注解配置类
    3. 判断第二步是否为空,如果为空则结束,反之对配置类集合进行排序
    4. 设置一些相关属性
    5. 生成注解配置类的解析类 ConfigurationClassParser
    6. do while 循环去解析配置类,(重点
    7. 将通过解析配置类获取到的类进行转化,变成 BeanDefinition 注册入IOC容器,(重点
    8. 判断配置类转化为 BeanDefinition 注入 IOC 容器中的时候是否有新的 Bean 加入
    9. 有的话,在进行下一轮的循环操作,(从6开始进行循环)

    根据我的总结,我们知道了主配置类是通过 parse 方法去解析,并将解析出来的类进行转化为 Bean 定义也既这个方法:loadBeanDefinitions

    好,下面我们的重点就移动到这两个方法。

    3.1 parse ,解析主配置类

    方法源码

    org.springframework.context.annotation.ConfigurationClassParser#parse

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        
        // 初始化属性
        this.deferredImportSelectors = new LinkedList<>();
    
        // 遍历配置类,分情况进行解析
        for (BeanDefinitionHolder holder : configCandidates) {
            // 拿到配置类对应的 bd
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                // 判断配置类的类型,更具类型进行解析
                if (bd instanceof AnnotatedBeanDefinition) {
                    // 主配置类默认进入这个进行解析
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                    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);
            }
        }
        // 解析 2.5 小节情况下的 Bean 导入
        processDeferredImportSelectors();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    这个方法干了两个比较重要的事情

    1. 解析配置类
    2. 解析 DeferredImportSelector 规则导入(延迟导入)

    那我们先来分析解析配置类 parse 源码

    1)parse

    org.springframework.context.annotation.ConfigurationClassParser#parse(org.springframework.core.type.AnnotationMetadata, java.lang.String)

    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
       processConfigurationClass(new ConfigurationClass(metadata, beanName));
    }
    
    • 1
    • 2
    • 3

    org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        // 判断是否跳过解析
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }
    
        // 第一次进入的时候,configurationClass的size为0,existingClass肯定为null,在此处处理configuration重复import
        // 如果同一个配置类被处理两次,两次都属于被import的则合并导入类,返回,如果配置类不是被导入的,则移除旧的使用新的配置类
        ConfigurationClass existingClass = this.configurationClasses.get(configClass);
        if (existingClass != null) {
            if (configClass.isImported()) {
                if (existingClass.isImported()) {
                    // 如果要处理的配置类configclass在已经分析处理的配置类记录中已存在,合并两者的importBy属性
                    existingClass.mergeImportedBy(configClass);
                }
                // Otherwise ignore new imported config class; existing non-imported class overrides it.
                return;
            }
            else {
                // Explicit bean definition found, probably replacing an import.
                // Let's remove the old one and go with the new one.
                this.configurationClasses.remove(configClass);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }
        }
    
        // Recursively process the configuration class and its superclass hierarchy.
        // 处理配置类,由于配置类可能存在父类(若父类的全类名是以java开头的,则除外),所有需要将configClass变成sourceClass去解析,然后返回sourceClass的父类。
        // 如果此时父类为空,则不会进行while循环去解析,如果父类不为空,则会循环的去解析父类
        // SourceClass的意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
        SourceClass sourceClass = asSourceClass(configClass);
        do {
            // 解析各种注解(真正解析方法)
            sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        while (sourceClass != null);
        // 将解析的配置类存储起来,这样回到parse方法时,能取到值
        this.configurationClasses.put(configClass, configClass);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    最终进入真正干活的方法

    org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {
    
        // Recursively process any member (nested) classes first
        // 递归解析配置类中的内部类,因为内部类也是一个配置类
        processMemberClasses(configClass, sourceClass);
    
        // Process any @PropertySource annotations
        // 如果配置类上加了@PropertySource注解,那么就解析加载properties文件,并将属性添加到spring上下文中
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
                logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                            "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }
    
        // Process any @ComponentScan annotations
        // 处理@ComponentScan或者@ComponentScans注解,并将扫描包下的所有bean转换成填充后的ConfigurationClass
        // 此处就是将自定义的bean加载到IOC容器,因为扫描到的类可能也添加了@ComponentScan和@ComponentScans注解,因此需要进行递归解析
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                // 解析@ComponentScan和@ComponentScans配置的扫描的包所包含的类
                // 比如 basePackages = cn.j3code, 那么在这一步会扫描出这个包及子包下的class,然后将其解析成BeanDefinition
                // (BeanDefinition可以理解为等价于BeanDefinitionHolder)
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                // 通过上一步扫描包cn.j3code,有可能扫描出来的bean中可能也添加了ComponentScan或者ComponentScans注解.
                //所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有ComponentScan和ComponentScans
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    // 判断是否是一个配置类,并设置full或lite属性
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(
                        holder.getBeanDefinition(), this.metadataReaderFactory)) {
                        // 通过递归方法进行解析
                        parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }
    
        // Process any @Import annotations
        // 处理@Import注解
        processImports(configClass, sourceClass, getImports(sourceClass), true);
    
        // Process any @ImportResource annotations
        // 处理@ImportResource注解,导入spring的配置文件
        AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            String[] resources = importResource.getStringArray("locations");
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            for (String resource : resources) {
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }
    
        // Process individual @Bean methods
        // 处理加了@Bean注解的方法,将@Bean方法转化为BeanMethod对象,保存再集合中
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }
    
        // Process default methods on interfaces
        // 处理接口的默认方法实现,从jdk8开始,接口中的方法可以有自己的默认实现,因此如果这个接口的方法加了@Bean注解,也需要被解析
        processInterfaces(configClass, sourceClass);
    
        // Process superclass, if any
        // 解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析
        if (sourceClass.getMetadata().hasSuperClass()) {
            String superclass = sourceClass.getMetadata().getSuperClassName();
            if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
                this.knownSuperclasses.put(superclass, configClass);
                // Superclass found, return its annotation metadata and recurse
                // 返回主配置类的父类,进行下一次的循环解析
                return sourceClass.getSuperClass();
            }
        }
    
        // No superclass -> processing is complete
        // 没有父类,主配置类解析完成,跳出循环
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    总结一下这个方法干了些啥:

    1. 先递归解析配置类中的内部类,因为内部类也是一个配置类
    2. 接着判断配置类中是否配置 @PropertySource 注解,如果有则解析
    3. 接着判断配置类中是否配置 @ComponentScan 或 @ComponentScans 注解,如果有则解析
    4. 接着判断配置类中是否配置 @Import 注解,如果有则解析
    5. 接着判断配置类中是否配置 @ImportResource 注解,如果有则解析
    6. 接着解析配置类中,所有标注 @Bean 注解的方法,将方法信息封装为 MethodMetadata 对象,待后续处理
    7. 解析配置类上实现的接口方法,如果有实现接口,则实现的方法信息也是封装为 MethodMetadata 对象,待后续处理
    8. 判断配置类是否有父类,有的话则循环解析其父类,反之则结束配置类解析

    以上步骤,从 2 到 8 开始每一步的解析流程都非常的复杂,如果我在这里一步步的每个都进行分析真的是在写书了。所以我只分析我认为常见且重要的一个步骤,既第三步,其它的我看源码都不是很难,大家有时间可以点进源码看看。

    分析第三步,包扫描。

    入口:

    Set<BeanDefinitionHolder> scannedBeanDefinitions =
        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    
    • 1
    • 2

    进入源码

    org.springframework.context.annotation.ComponentScanAnnotationParser#parse

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        // 生成 bd 扫描器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                                                                                    componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    
        // 下面是一系列的给扫描器赋值操作,例如设置只扫描XXX规则、排除XXX规则扫描
        
        // ....
        
        // 真正开始去扫描的
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    doScan 源码

    org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        // 创建存放扫描出来的 bd 集合
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        // 循环解析传入进来的包路径
        for (String basePackage : basePackages) {
            // 这个就是根据我们传入进来的包路径进行查找符合规则的 bd
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            // 遍历符合扫描规则的 bd
            for (BeanDefinition candidate : candidates) {
                // 给 bd 设置属性
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
    
                // 生成 beanName
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    
                // 根据生成的 bd 类型执行对应的初始化方法
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
    
                // 检查 bd 是否符合一个 Bean 的规则(这里的判断是需要的,因为扫描出来的bd只是符合扫描规则,不一定符合生成 Bean 的规则)
                if (checkCandidate(beanName, candidate)) {
                    
                    // 符合规则,那么进行封装,注册 bd
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        // 返回扫描出来且符合生成 Bean 规则的 bd
        return beanDefinitions;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    总结一下这个方法干了些啥:

    1. 循环遍历传进来的包路径集合
    2. 通过 findCandidateComponents 方法找到包路径下符合扫描规则的 bd
    3. 循环扫描出来的 bd ,给其初始化相关属性
    4. 判断 bd 是否符合生成 Bean 的要求
    5. 如果符合则进行 Bean 定义的注入,反之则不进行注入

    那么很显然重点方法就在于这个 bd 是如何被找出来的,也即 findCandidateComponents 方法的执行逻辑。

    废话不多说,方法源码如下

    org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        // componentsIndex对象包含了扫描“META-INF/spring.components”文件后封装起来的需要注册的bean的信息,在这里与来basePackage同时进行处理(spring.components 与 basePackage同时满足才会被处理),
        //如果“META-INF/spring.components”文件不存在,则 componentsIndex 为 null,反之则会在 ClassPathBeanDefinitionScanner # setResourceLoader 中对其进行赋值
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            // 判断 META-INF/spring.components 文件中配置的注册 Bean 是否符合 basePackage 的包路径,符合则注入
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            // 根据包路径扫描
            return scanCandidateComponents(basePackage);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如果我们不配置如下文件,则默认会走 scanCandidateComponents 方法。

    在这里插入图片描述

    好了,理清楚这个分支走向之后,进入我们的 scanCandidateComponents 方法源码

    org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        // 初始化一个符合扫描规则的 bd 存放集合
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            // 拼接, 加上了 "classpath*:" 前缀和 "**/*.class" 后缀, 大致可以理解为仅扫描当前类路径下的,且为当前包及其子包下的 class 文件
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            // 获取到所有 class 文件
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            // 遍历 class
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 是否满足条件,这里是 Filter 筛选,这里是循环两个扫描规则,第一个是排除规则集合、一个是扫描规则集合
                        if (isCandidateComponent(metadataReader)) {
                            // 创建一个 bd,类型为 ScannedGenericBeanDefinition
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            // 设置相关属性
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            // 再次判断这个类是否符合条件(不是内部类并且是一个具体类)
                            // 具体类:不是接口也不是抽象类,如果是抽象类则需要带有 @Lookup 注解
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                // 符合要求,将 bd 放入集合
                                candidates.add(sbd);
                            }
                            else {
                                if (debugEnabled) {
                                    logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            }
                        }
                        else {
                            if (traceEnabled) {
                                logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                    }
                }
                else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        // 返回扫描获得的 bd 集合
        return candidates;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    总结一下这个方法干了些啥:

    1. 根据 basePackage 拼接 class 文件扫描路径
    2. 调用资源文件获取工具,根据第一步拼接的路径将所有符合要求的 class 文件获取出来
    3. 遍历资源文件集合
    4. 判断资源文件是否可读
    5. 根据资源文件封装成 MetadataReader 对象进行后续步骤
    6. 判断 MetadataReader 是否符合 TypeFilter 规则
    7. 符合第六步的规则之后,根据 MetadataReader 生成 ScannedGenericBeanDefinition 对象并设置相关属性
    8. 判断生成的 bd 是否是一个具体的类,符合 Bean 要求的最后一个判断
    9. 判断都通过后,放入 bd 集合,待所有资源文件都遍历完成之后,向上层返回 bd 集合。

    好了,根据包路径扫描符合要求的 Bean 并封装成 Bean 定义注册进 BeanFactory 的容器中的实现流程我们已经分析完成了,也意味着我们的 parse 方法分析告一段落了。

    2)processDeferredImportSelectors

    这个方法是处理 DeferredImportSelector 的导入规则,既延迟导入。

    先来看他的类继承图:

    在这里插入图片描述

    该图很清楚的让我们知道 DeferredImportSelector 是 ImportSelector 的子类,表示延迟处理自定义的 Bean 导入规则。

    使用案例:

    1,创建自定义类,实现 DeferredImportSelector 接口

    public class MyDeferredImportSelector implements DeferredImportSelector {
    
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            // 将 Bean 的全限定类名传进入
            return new String[]{"cn.j3code.studyspring.service.UserDServiceImpl"};
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2,修改配置类

    @ComponentScan(value = "cn.j3code.studyspring.life")
    @Import(value = {MyDeferredImportSelector.class})
    @Configuration
    public class LifeConfiguration {}
    
    • 1
    • 2
    • 3
    • 4

    那么此时,程序运行的时候就会来到 processDeferredImportSelectors 方法进行处理 MyDeferredImportSelector 类。

    ok,进入 processDeferredImportSelectors 方法源码

    org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors

    private void processDeferredImportSelectors() {
        // 获取 deferredImportSelectors 属性值
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        if (deferredImports == null) {
            return;
        }
    
        // 排序
        Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
        // 遍历 deferredImports 中导入的 DeferredImportSelector 类型
        for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            // 获取到配置类
            ConfigurationClass configClass = deferredImport.getConfigurationClass();
            try {
                // 调用配置类中的 selectImports 方法获取注入的值(全限定类名数组)
                String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                // 执行 processImports 方法进行解析注册
                processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configClass.getMetadata().getClassName() + "]", ex);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    总结一下这个方法干了些啥:

    1. 获取 this.deferredImportSelectors 的值(存放实现 DeferredImportSelector 接口的类)
    2. 排序并遍历集合
    3. 调用 DeferredImportSelector 接口实现类的 selectImports 方法获取要导入的全限定类名数组值
    4. 通过调用 processImports(这个方法在 parse 解析方法中有) 方法注册导入进来的全限定类名数组

    方法的逻辑不是很难,在上面的总结处已经说的很明白了。那现在还有一个疑问就是 this.deferredImportSelectors 的值是如何放进去的,也即 MyDeferredImportSelector 类如何添加到 deferredImportSelectors 属性中的。

    那这就不得不看 parse 中解析 Imports 注解的这个方法了,源码如下:

    org.springframework.context.annotation.ConfigurationClassParser#processImports

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                                Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
        // ...
        // 遍历 Imports 导入的所有类
        for (SourceClass candidate : importCandidates) {
    
            // ...
    
            // 判断导入的类是否是 DeferredImportSelector 类型,如果是那么则不进行解析,而是放入 deferredImportSelectors 属性集合中,交给 processDeferredImportSelectors 方法进行解析
            if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                this.deferredImportSelectors.add(
                    new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
            }
    
            // ...
        }
    
        // ...
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    方法代码很多,我省略了与我们要的答案无关的代码,只留下了向 this.deferredImportSelectors 属性中添加值的代码。

    可以看出在解析 Imports 注解时,判断 Imports 中的 class ,如果是实现了 DeferredImportSelector 接口那么就放入 deferredImportSelectors 属性集合中,这就是我们要的答案。

    好了 processDeferredImportSelectors 这个方法也给大家分析完了。

    3.2 loadBeanDefinitions ,配置类转化为 Bean 定义

    上面的 parse 解析逻辑只是将我们的主配置类进行了解析,并且除了包扫描出来的 class 封装成了 Bean 定义注册进了 BeanFacotry 中外,其它像 Import 、@Bean 形式的注入 Bean 还没有对其进行封装 Bean 定义,其还只是一个元数据的状态,所以 loadBeanDefinitions 方法,就是加载这些,将其变为 Bean 定义并且注入到 BeanFactory 中的一个逻辑。

    那还记得这个入口代码在哪里嘛,如下:

    this.reader.loadBeanDefinitions(configClasses);
    
    • 1

    进入方法

    org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        // 循环遍历加载的配置类
        for (ConfigurationClass configClass : configurationModel) {
            // 针对每个配置类加载出来的数据,进行挨个加载
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在进入 loadBeanDefinitionsForConfigurationClass 方法

    org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

    private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
                                                          TrackedConditionEvaluator trackedConditionEvaluator) {
    
        // 判断配置类是否需要跳过
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }
    
        // 判断该配置类是导入进来的吗
        if (configClass.isImported()) {
            // 封装该配置类为 Bean 定义注册进 BeanFactory
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        
        // 获取该类的所有 @Bean 注解标注的方法信息
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            // 将 @Bean 标注的方法封装为 Bean 定义进行注入
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
        
        // 获取配置类上通过 @ImportedResources 注解导入的 xml 配置类,并开始解析 xml 配置类进行注册 Bean 定义
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        // 获取配置类上通过 @Import 注解导入的 ImportBeanDefinitionRegistrar 类型的类,执行其导入 Bean 的方法进行 Bean 定义的注册
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    总结一下这个方法干了些啥:

    1. 判断该配置类是否需要跳过加载
    2. 判断该配置类是否是 @Ipmort 注解导入的,如果是则将自身封装成 Bean 定义进行注入
    3. 获取配置类的所有 @Bean 标注的方法进行 Bean 定义的注入
    4. 获取配置类上 @ImportedResources 注解导入的 XML 配置类,并解析 XML 配置类进行注册 Bean 定义
    5. 获取配置类上 @Import 注解导入的 ImportBeanDefinitionRegistrar 类型的类,执行其 registerBeanDefinitions 方法进行 Bean 定义的注册。

    经过以上的源码分析,配置类的解析终于是告一段落了,其将所有人为配置的 Bean 相关的信息全部都加载封装进了 BeanFactory 中的 beanDefinitionMap 属性中。

    四、invokeBeanFactoryPostProcessors 执行流程图

    画图高手为了能让大家更清楚的了解这个方法的各个执行流程,所以画了下面的流程图供大家参考。

    在这里插入图片描述

    好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见


    • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

    • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

    • 感谢您的阅读,十分欢迎并感谢您的关注。

  • 相关阅读:
    Docker镜像制作
    【计算机网络期末复习】选择题①1~50
    Leetcode 剑指 Offer II 050. 路径总和 III
    基于docker构建容器镜像
    SwiftUI 开发经验之我希望我作为一个新人了解从头开始构建 iOS 应用程序
    手把手教你用站长工具综查询网站域名在各个平台的权重情况 站长工具综查询
    A Framework to Evaluate Fusion Methods for Multimodal Emotion Recognition
    【小黑嵌入式系统第三课】嵌入式系统硬件平台(一)——概述、总线、存储设备(RAM&ROM&FLASH)
    【数据结构】树和二叉树的概念及结构
    面向项目版本差异性的漏洞识别技术研究
  • 原文地址:https://blog.csdn.net/qq_40399646/article/details/127462825