Spring源码 @ComponentScan源码流程

调用 ComponentScan 的地方如下所示:

Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass) throws IOException {
        this.processMemberClasses(configClass, sourceClass);
        Iterator var3 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();

        AnnotationAttributes importResource;
        while(var3.hasNext()) {
            importResource = (AnnotationAttributes)var3.next();
            if (this.environment instanceof ConfigurableEnvironment) {
                this.processPropertySource(importResource);
            } else {
                this.logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }
        //!!!
        //看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ////!!!
        Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            Iterator var13 = componentScans.iterator();

            while(var13.hasNext()) {
                AnnotationAttributes componentScan = (AnnotationAttributes)var13.next();
                Set scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                Iterator var7 = scannedBeanDefinitions.iterator();

                while(var7.hasNext()) {
                    BeanDefinitionHolder holder = (BeanDefinitionHolder)var7.next();
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }

                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        this.parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

        this.processImports(configClass, sourceClass, this.getImports(sourceClass), true);
        if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
            importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
            String[] resources = importResource.getStringArray("locations");
            Class readerClass = importResource.getClass("reader");
            String[] var20 = resources;
            int var21 = resources.length;

            for(int var22 = 0; var22 < var21; ++var22) {
                String resource = var20[var22];
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }

        Set beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
        Iterator var16 = beanMethods.iterator();

        while(var16.hasNext()) {
            MethodMetadata methodMetadata = (MethodMetadata)var16.next();
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

        this.processInterfaces(configClass, sourceClass);
        if (sourceClass.getMetadata().hasSuperClass()) {
            String superclass = sourceClass.getMetadata().getSuperClassName();
            if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
                this.knownSuperclasses.put(superclass, configClass);
                return sourceClass.getSuperClass();
            }
        }
        return null;
    }

我们先来看看代码如何从最开始流程一步一步调用到这个函数的:
要应用 注解需要这么一行代码:

ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);

进入到 AnnotationConfigApplicationContext:
看过源码的应该很熟悉这个,基本上是第一步:


image.png

然后一步一步调用:
整个 bean 实例化初始化的流程:


image.png

invokeBeanFactoryPostProcessors:


image.png

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry):
代码太长截图一页显示不出来,只贴出关键部分:
image.png

继续


image.png

image.png

终于到了关键的地方:
image.png

注意这一行:
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);

所有配置类注解都在这里创建。
创建的时候:

this.componentScanParser = new ComponentScanAnnotationParser(environment, resourceLoader, componentScanBeanNameGenerator, registry);
image.png

继续看

parser.parse(candidates);
image.png
image.png
image.png

这就回到了我们最开始的地方:
所有扫描出来的 bean 都在这里解析


image.png

主业务流程都在这个 parse 中 doscan 函数中:


image.png

扫描所有的配置类:
image.png

这个函数里,做class path 的拼接,读取 class 信息
image.png

下面这个函数中判断是否实例化,isCandidateComponent 处理中还有 filter 的相关处理。

if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
                                if (debugEnabled) {
                                    this.logger.debug("Identified candidate component class: " + resource);
                                }

                                candidates.add(sbd);
                            }

你可能感兴趣的:(Spring源码 @ComponentScan源码流程)