10、SpringBoot 启动 刷新应用上下文 自动装配解析(二)

书接上文中最重要的两个方法,我们先看第一个,debug进入

    public void parse(Set<beandefinitionholder> configCandidates) {
                // &#x4F20;&#x5165;&#x7684;&#x5E26;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x4E00;&#x4E2A;&#x96C6;&#x5408;&#xFF0C;&#x4F46;&#x662F;&#x6211;&#x4EEC;&#x672C;&#x6B21;debug&#x662F;springboot&#x7B2C;&#x4E00;&#x6B21;&#x542F;&#x52A8;&#xFF0C;&#x6B64;&#x65F6;&#x8FD9;&#x4E2A;&#x7ED3;&#x5408;&#x53EA;&#x6709;&#x542F;&#x52A8;&#x7C7B;&#x8FD9;&#x4E00;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;
        for (BeanDefinitionHolder holder : configCandidates) {
                        // &#x83B7;&#x53D6; BeanDefinition
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                                // &#x6839;&#x636E;&#x4E0D;&#x540C;&#x7684;BeanDefinition&#x8FDB;&#x5165;&#x4E0D;&#x540C;&#x7684;&#x89E3;&#x6790;&#x5206;&#x652F;&#xFF0C;
                                // &#x5176;&#x5B9E;&#x5C31;&#x662F;&#x8C03;&#x7528;&#x4E86;&#x4E0D;&#x540C;&#x7684;&#x91CD;&#x8F7D;&#x89E3;&#x6790;&#x65B9;&#x6CD5;&#xFF0C;&#x6700;&#x7EC8;&#x8FDB;&#x5165;&#x540E;&#x9762;&#x8FDB;&#x5165;&#x4E86;&#x540C;&#x4E00;&#x65B9;&#x6CD5;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x4EEC;&#x53EA;&#x9700;&#x8981;&#x770B;&#x8FD9;&#x4E00;&#x6B21;&#x7684;debug&#x7684;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x5373;&#x53EF;&#xFF0C;&#x4E0B;&#x9762;&#x7684;&#x4E24;&#x4E2A;&#x5206;&#x652F;&#x5C31;&#x4E0D;&#x7528;&#x770B;&#x4E86;
                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);
            }
        }
                // &#x5EF6;&#x8FDF;&#x5BFC;&#x5165;&#x9009;&#x62E9;&#x5668;&#x6301;&#x6709;&#x8005;&#x5F00;&#x59CB;&#x6267;&#x884C;&#xFF0C;&#x8BE5;&#x6B65;&#x9AA4;&#x548C;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x903B;&#x8F91;&#x6709;&#x5173;&#xFF0C;&#x8BF7;&#x770B;&#x6807;&#x9898;1.2
                // &#x8FD9;&#x91CC;&#x63D0;&#x524D;&#x8BF4;&#x4E00;&#x4E0B;&#xFF0C;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;@import&#x4E2D;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#x5982;&#x679C;&#x5B9E;&#x73B0;&#x4E86;DeferredImportSelector&#x63A5;&#x53E3;&#xFF0C;&#x5C31;&#x4F1A;&#x5B58;&#x5728;deferredImportSelectorHandler&#x5C5E;&#x6027;
                // &#x5728;&#x7C7B;&#x89E3;&#x6790;&#x5B8C;&#x6210;&#x540E;&#x4F1A;&#x8C03;&#x7528;deferredImportSelectorHandler&#x5C5E;&#x6027;&#x7684;process&#x65B9;&#x6CD5;&#xFF0C;&#x5F00;&#x59CB;&#x6267;&#x884C;&#x5BFC;&#x5165;
        this.deferredImportSelectorHandler.process();
    }
</beandefinitionholder>

继续debug

    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
                // &#x524D;&#x9762;&#x8BF4;&#x7684;&#x4E09;&#x4E2A;&#x89E3;&#x6790;&#x91CD;&#x8F7D;&#x65B9;&#x6CD5;&#xFF0C;&#x6700;&#x7EC8;&#x90FD;&#x4F1A;&#x8C03;&#x7528;&#x8FD9;&#x4E00;&#x4E2A;&#x65B9;&#x6CD5;
        processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
    }
    protected void processConfigurationClass(ConfigurationClass configClass, Predicate<string> filter) throws IOException {
                // &#x5224;&#x65AD;&#x8FD9;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;&#x4E0A;&#x9762;&#x6709;&#x6CA1;&#x6709; @Condition &#x6CE8;&#x89E3;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x5224;&#x65AD;&#x662F;&#x5426;&#x6210;&#x7ACB;&#xFF0C;&#x4E0D;&#x6210;&#x7ACB;&#x4E0D;&#x9700;&#x8981;&#x89E3;&#x6790;
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }

                // &#x4ECE;&#x5DF2;&#x7ECF;&#x89E3;&#x6790;&#x8FC7;&#x7684;&#x7C7B;&#x96C6;&#x5408;&#x4E2D;&#x83B7;&#x53D6;&#x8FD9;&#x4E2A;&#x7C7B;
        ConfigurationClass existingClass = this.configurationClasses.get(configClass);
                // &#x5982;&#x679C;&#x5DF2;&#x7ECF;&#x5B58;&#x5728;&#x4E86;
        if (existingClass != null) {
                        // &#x5219;&#x5224;&#x65AD;&#x8FD9;&#x4E2A;&#x7C7B;&#x662F;&#x4E0D;&#x662F;&#x4ECE;&#x5176;&#x4ED6;&#x7C7B;&#x91CC;&#x9762;&#x5BFC;&#x5165;&#x7684;
            if (configClass.isImported()) {
                                // &#x5224;&#x65AD;&#x5DF2;&#x7ECF;&#x5B58;&#x5728;&#x7684;&#x7C7B;&#x662F;&#x4E0D;&#x662F;&#x4ECE;&#x5176;&#x4ED6;&#x7C7B;&#x91CC;&#x5BFC;&#x5165;&#x7684;
                if (existingClass.isImported()) {
                                        // &#x5982;&#x679C;&#x6210;&#x7ACB;&#x5219;&#x5C06;&#x5BFC;&#x5165;&#x7C7B;&#x5408;&#x5E76;
                    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.

                                // &#x5982;&#x679C;&#x8FD9;&#x4E2A;&#x7C7B;&#x4E0D;&#x662F;&#x4ECE;&#x5176;&#x4ED6;&#x7C7B;&#x5BFC;&#x5165;&#xFF0C;&#x5219;&#x4ECE;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;&#x5220;&#x9664;
                this.configurationClasses.remove(configClass);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }
        }

        // Recursively process the configuration class and its superclass hierarchy.

                // &#x5C06;&#x914D;&#x7F6E;&#x7C7B;&#x5BF9;&#x8C61;ConfigurationClass&#xFF0C;&#x5305;&#x88C5;&#x6210; &#x6E90;&#x7C7B;
        SourceClass sourceClass = asSourceClass(configClass, filter);
        do {
                        // &#x5F00;&#x59CB;&#x6267;&#x884C;&#x771F;&#x6B63;&#x7684;&#x89E3;&#x6790;
            sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
        }
        while (sourceClass != null);

                // &#x5C06;&#x89E3;&#x6790;&#x8FC7;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x52A0;&#x5165;&#x914D;&#x7F6E;&#x7C7B;&#x96C6;&#x5408;&#xFF0C;&#x540E;&#x9762;&#x8F6C;&#x6362;&#x4E3A;BeanDefinition
        this.configurationClasses.put(configClass, configClass);
    }
</string>

千呼万唤始出来,到了真正解析的地方,在继续之前我们有必要先了解一下 ConfigurationClass这个类,后续解析出啦的信息都会存到这个类中

// &#x88AB;final&#x4FEE;&#x9970;&#xFF0C;&#x4E0D;&#x53EF;&#x7EE7;&#x627F;
final class ConfigurationClass {

        // &#x62A5;&#x9519;&#x4E86;&#x914D;&#x7F6E;&#x7C7B;&#x7684;&#x6CE8;&#x89E3;&#x5143;&#x6570;&#x636E;&#x4FE1;&#x606F;
    private final AnnotationMetadata metadata;

        // &#x914D;&#x7F6E;&#x7C7B;&#x8D44;&#x6E90;
    private final Resource resource;

    // &#x914D;&#x7F6E;&#x7C7B;&#x540D;&#x79F0;
    private String beanName;

        // &#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x901A;&#x8FC7;&#x90A3;&#x4E2A;&#x7C7B;&#x5BFC;&#x5165;&#x7684;
    private final Set<configurationclass> importedBy = new LinkedHashSet<>(1);

        // &#x914D;&#x7F6E;&#x7C7B;&#x6240;&#x6709;&#x7684;&#x88AB;@bean&#x6CE8;&#x89E3;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x5305;&#x62EC;&#x4ED6;&#x7684;&#x63A5;&#x53E3;&#x548C;&#x7236;&#x7C7B;&#x4E2D;&#x88AB;@bean&#x6807;&#x6CE8;&#x7684;&#x65B9;&#x6CD5;
    private final Set<beanmethod> beanMethods = new LinkedHashSet<>();

        // &#x914D;&#x7F6E;&#x7C7B;&#x4E2D;@ImportResource&#x6CE8;&#x89E3;&#x6807;&#x6CE8;&#x7684;&#x8D44;&#x6E90;
    private final Map<string, class<? extends beandefinitionreader>> importedResources = new LinkedHashMap<>();

        // &#x914D;&#x7F6E;&#x7C7B;&#x4E2D;@import&#x4E2D;&#x7684;&#x7C7B;&#xFF0C;&#x5E76;&#x4E14;&#x8FD9;&#x4E2A;&#x7C7B;&#x5B9E;&#x73B0;&#x4E86;ImportBeanDefinitionRegistrar&#x63A5;&#x53E3;
    private final Map<importbeandefinitionregistrar, annotationmetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>();

        // &#x914D;&#x7F6E;&#x7C7B;&#x4E2D;@bean&#x6CE8;&#x89E3;&#x6807;&#x6CE8;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x4E0A;&#x9762;&#x8FD8;&#x6709;@Condition&#x6CE8;&#x89E3;&#xFF0C;&#x4F46;&#x662F;&#x4E0D;&#x6EE1;&#x8DB3;&#x6761;&#x4EF6;&#xFF0C;&#x8981;&#x8DF3;&#x8FC7;&#x89E3;&#x6790;&#x7684;&#x65B9;&#x6CD5;&#x4E3A;
    final Set<string> skippedBeanMethods = new HashSet<>();

        // &#x7701;&#x7565;&#x6240;&#x6709;&#x7684;&#x65B9;&#x6CD5;
}
</string></importbeandefinitionregistrar,></string,></beanmethod></configurationclass>

熟悉了这个类之后我们现在开始debug,我们先看一下整体的解析流程

上面8步中,都是Spring中的逻辑,我们都不看了,本次主要是看自动装配,我们只需要看第4步即可

    protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass, Predicate<string> filter)
            throws IOException {
                // &#x7B2C;&#x4E00;&#x6B65;&#xFF0C;&#x9996;&#x5148;&#x5224;&#x65AD;&#x4F20;&#x5165;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x6709;&#x6CA1;&#x6709;@Component&#x6CE8;&#x89E3;&#xFF0C;&#x5982;&#x679C;&#x6709;&#xFF0C;&#x5219;&#x9700;&#x8981;&#x68C0;&#x67E5;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;&#x6709;&#x6CA1;&#x6709;&#x5185;&#x90E8;&#x7C7B;&#xFF0C;&#x5E76;&#x4E14;&#x8FD9;&#x4E2A;&#x5185;&#x90E8;&#x7C7B;&#x662F;&#x4E0D;&#x662F;&#x914D;&#x7F6E;&#x7C7B;
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // Recursively process any member (nested) classes first
            processMemberClasses(configClass, sourceClass, filter);
        }

                // &#x7B2C;&#x4E8C;&#x6B65;&#xFF0C;&#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x7C7B;&#x4E0A;&#x9762;&#x7684;@PropertySource&#x6CE8;&#x89E3;&#x548C;@PropertySources&#x6CE8;&#x89E3;&#xFF0C;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
                logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }

                // &#x7B2C;&#x4E09;&#x6B65;&#xFF0C;&#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x7C7B;&#x4E0A;&#x9762;&#x7684;@ComponentScan&#x6CE8;&#x89E3;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        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
                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
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

                // &#x7B2C;&#x56DB;&#x6B65;&#xFF0C;&#x89E3;&#x6790;&#x914D;&#x7F6E;&#x7C7B;&#x4E0A;&#x9762;&#x7684;@Import&#x6CE8;&#x89E3;&#xFF0C;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x903B;&#x8F91;&#x6709;&#x5173;&#xFF0C;&#x4E5F;&#x662F;&#x6211;&#x4EEC;&#x540E;&#x9762;&#x91CD;&#x70B9;&#x5173;&#x6CE8;&#x7684;&#xFF0C;&#x8BF7;&#x770B;&#x6807;&#x9898;1.1
                // &#x5173;&#x4E8E;getImports&#x65B9;&#x6CD5;&#xFF0C;&#x4E00;&#x4E2A;&#x6CE8;&#x89E3;&#x53EF;&#x80FD;&#x662F;&#x88AB;&#x591A;&#x4E2A;&#x6CE8;&#x89E3;&#x6807;&#x6CE8;&#xFF0C;&#x5C31;&#x50CF;&#x6211;&#x4EEC;&#x8FD9;&#x6B21;&#x8981;&#x770B;&#x7684;@SpringBootApplication&#xFF0C;&#x5B83;&#x91CC;&#x9762;&#x6709; @SpringBootConfiguration &#x548C; @EnableAutoConfiguration &#x4E24;&#x4E2A;&#x6CE8;&#x89E3;
                // &#x800C;&#x8FD9;&#x4E24;&#x4E2A;&#x6CE8;&#x89E3;&#x91CC;&#x9762;&#x53C8;&#x90FD;&#x88AB; @Import&#x6CE8;&#x89E3;&#x6807;&#x6CE8;&#xFF0C;&#x6240;&#x4EE5;&#x5728;&#x89E3;&#x6790;@Import&#x6CE8;&#x89E3;&#x524D;&#xFF0C;&#x8981;&#x5148;&#x627E;&#x5230;&#x6240;&#x6709;&#x7684;@Import&#x6CE8;&#x89E3;&#xFF0C;&#x8FD9;&#x91CC;&#x4F7F;&#x7528;&#x7684;&#x662F;&#x9012;&#x5F52;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x800C;&#x4E14;&#x6BCF;&#x4E2A;@Import&#x6CE8;&#x89E3;&#x53EF;&#x4EE5;&#x5BFC;&#x5165;&#x591A;&#x4E2A;&#x7C7B;&#xFF0C;&#x6211;&#x4EEC;&#x5C31;&#x4E0D;&#x770B;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x4E86;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x77E5;&#x9053;&#x6211;&#x4EEC;&#x518D;debug&#x65F6;&#xFF0C;
                // &#x7B2C;&#x4E00;&#x6B21;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x5C31;&#x662F; springboot &#x7684;&#x542F;&#x52A8;&#x7C7B;&#xFF0C;&#x800C;&#x542F;&#x52A8;&#x7C7B;&#x4E0A;&#x7684;@SpringBootApplication&#x6700;&#x7EC8;&#x4F1A;&#x89E3;&#x6790;&#x51FA;&#x6765;&#x4E24;&#x4E2A; @Import &#x5BFC;&#x5165;&#x7684;&#x7C7B;
        processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

                // &#x7B2C;&#x4E94;&#x6B65;&#xFF0C;&#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x7C7B;&#x4E0A;&#x9762;&#x7684;@ImportResource&#x6CE8;&#x89E3;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        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);
            }
        }

                // &#x7B2C;&#x516D;&#x6B65;&#xFF0C;&#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x7C7B;&#x91CC;&#x9762;&#x6807;&#x5FD7;@Bean&#x6CE8;&#x89E3;&#x7684;&#x65B9;&#x6CD5;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        Set<methodmetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

        // &#x7B2C;&#x4E03;&#x6B65;&#xFF0C;&#x5224;&#x65AD;&#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x5426;&#x6709;&#x5B9E;&#x73B0;&#x63A5;&#x53E3;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x68C0;&#x67E5;&#x63A5;&#x53E3;&#x4E2D;&#x7684;&#x65B9;&#x6CD5;&#x662F;&#x5426;&#x6709;@bean&#x6CE8;&#x89E3;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x8FDB;&#x884C;&#x89E3;&#x6790;
        processInterfaces(configClass, sourceClass);

                // &#x7B2C;&#x516B;&#x6B65;&#xFF0C;&#x5224;&#x65AD;&#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x5426;&#x6709;&#x7236;&#x7C7B;&#xFF0C;&#x5982;&#x679C;&#x6709;&#xFF0C;&#x83B7;&#x53D6;&#x7236;&#x7C7B;&#x8FD4;&#x56DE;&#xFF0C;&#x5728;&#x8FDB;&#x884C;&#x4E00;&#x6B21;&#x89E3;&#x6790;
        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();
            }
        }

                // &#x6CA1;&#x6709;&#x7236;&#x7C7B;&#xFF0C;&#x5219;&#x89E3;&#x6790;&#x5B8C;&#x6210;
        return null;
    }
</methodmetadata></beandefinitionholder></annotationattributes></string>

1.1、 processImports 解析

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<sourceclass> importCandidates, Predicate<string> exclusionFilter,
            boolean checkForCircularImports) {
                // &#x5224;&#x65AD;&#x662F;&#x5426;&#x6709;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;
        if (importCandidates.isEmpty()) {
            return;
        }

                // checkForCircularImports&#x4F20;&#x5165;&#x5C31;&#x662F;true,isChainedImportOnStack&#x65B9;&#x6CD5;&#x6267;&#x884C;&#x7ED3;&#x679C;&#x4E5F;&#x662F;true
        if (checkForCircularImports && isChainedImportOnStack(configClass)) {
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
        }
        else {
            this.importStack.push(configClass);
            try {
                                // &#x904D;&#x5386;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;
                for (SourceClass candidate : importCandidates) {
                                        // &#x5982;&#x679C;&#x8FD9;&#x4E2A;&#x7C7B;&#x5B9E;&#x73B0;&#x4E86;ImportSelector&#x8FD9;&#x4E2A;&#x63A5;&#x53E3;
                    if (candidate.isAssignable(ImportSelector.class)) {
                        // Candidate class is an ImportSelector -> delegate to it to determine imports
                        Class<?> candidateClass = candidate.loadClass();
                                                // &#x5C06;&#x8FD9;&#x4E2A;&#x7C7B;&#x5B9E;&#x4F8B;&#x5316;
                        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                this.environment, this.resourceLoader, this.registry);
                        Predicate<string> selectorFilter = selector.getExclusionFilter();
                        if (selectorFilter != null) {
                            exclusionFilter = exclusionFilter.or(selectorFilter);
                        }
                                                // &#x5224;&#x65AD;&#x8FD9;&#x4E2A;&#x7C7B;&#x662F;&#x5426;&#x5B9E;&#x73B0;&#x4E86;DeferredImportSelector&#x63A5;&#x53E3;&#xFF0C;&#x5982;&#x679C;&#x5B9E;&#x73B0;&#x4E86;&#x5C31;&#x52A0;&#x5165;deferredImportSelectorHandler&#x5904;&#x7406;&#x5668;&#xFF0C;&#x8FD9;&#x4E00;&#x6B65;&#x548C;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x6709;&#x5173;&#xFF0C;&#x6240;&#x4EE5;&#x6574;&#x4E2A;&#x6D41;&#x7A0B;&#x4E2D;&#x53EA;&#x6709;&#x8FD9;&#x4E00;&#x6B65;&#x662F;&#x6211;&#x4EEC;&#x5173;&#x6CE8;&#x7684;&#x91CD;&#x70B9;
                                                // &#x6211;&#x4EEC;&#x6240;&#x719F;&#x77E5;&#x7684;@SpringBootApplication &#x4E2D;&#x5C31;&#x6709;&#x4E00;&#x4E2A;@AutoConfigurationPackage&#x6CE8;&#x89E3;&#xFF0C;
                                                // &#x800C;&#x6574;&#x4E2A;@AutoConfigurationPackage&#x6CE8;&#x89E3;&#x4E2D;&#x5C31;&#x6709; @Import&#x6CE8;&#x89E3;&#xFF0C;&#x4ED6;&#x5BFC;&#x5165;&#x7684;&#x7C7B;AutoConfigurationImportSelector&#xFF0C;&#x5C31;&#x5B9E;&#x73B0;&#x4E86;&#x8FD9;&#x4E2A;&#x63A5;&#x53E3;
                        if (selector instanceof DeferredImportSelector) {
                            this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                        }
                        else {
                                                        // &#x5426;&#x5219;&#x5C31;&#x518D;&#x6B21;&#x8FDB;&#x884C;&#x4E00;&#x6B21;&#x8981;&#x5BFC;&#x5165;&#x7C7B;&#x7684;&#x89E3;&#x6790;&#xFF0C;&#x4E0D;&#x8FC7;
                            String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                            Collection<sourceclass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                            processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                        }
                    }
                                        // &#x5982;&#x679C;&#x8FD9;&#x4E2A;&#x7C7B;&#x5B9E;&#x73B0;&#x4E86;ImportBeanDefinitionRegistrar&#x8FD9;&#x4E2A;&#x63A5;&#x53E3;&#xFF0C;&#x5C31;&#x5C06;&#x8FD9;&#x4E2A;&#x7C7B;&#x5B9E;&#x4F8B;&#x5316;&#xFF0C;&#x7136;&#x540E;&#x5B58;&#x5165;&#x5F53;&#x524D;&#x6B63;&#x5728;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;
                    else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                        // Candidate class is an ImportBeanDefinitionRegistrar ->
                        // delegate to it to register additional bean definitions
                        Class<?> candidateClass = candidate.loadClass();
                        ImportBeanDefinitionRegistrar registrar =
                                ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                        this.environment, this.resourceLoader, this.registry);
                        configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                    }
                                        // &#x5982;&#x679C;&#x8FD9;&#x4E2A;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#x4E0A;&#x9762;&#x4E24;&#x4E2A;&#x63A5;&#x53E3;&#x90FD;&#x6CA1;&#x5B9E;&#x73B0;&#xFF0C;&#x5219;&#x5C31;&#x5BF9;&#x8FD9;&#x4E2A;&#x7C7B;&#x8FDB;&#x884C;&#x89E3;&#x6790;&#xFF0C;&#x53EF;&#x80FD;&#x8FD9;&#x4E2A;&#x7C7B;&#x662F;&#x4E00;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;
                    else {
                        // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                        // process it as an @Configuration class
                        this.importStack.registerImport(
                                currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                        processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                    }
                }
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                        configClass.getMetadata().getClassName() + "]", ex);
            }
            finally {
                this.importStack.pop();
            }
        }
    }
</sourceclass></string></string></sourceclass>

debug进入 deferredImportSelectorHandlerhandle方法
在我们开篇第一个方法,parse方法,最后面就发现,在配置类解析完成后,有 deferredImportSelectorHandler方法的回调

        public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
                        // &#x5C06;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#xFF0C;&#x5305;&#x88C5;&#x6210; DeferredImportSelectorHolder&#x7C7B;&#x578B;&#xFF0C;&#x7136;&#x540E;&#x5C06;&#x5B83;&#x52A0;&#x5165;&#x5230;deferredImportSelectors&#x96C6;&#x5408;&#x4E2D;&#xFF0C;&#x5728;&#x4E0A;&#x9762;&#x6211;&#x4EEC;&#x5C31;&#x53D1;&#x73B0;&#xFF0C;&#x914D;&#x7F6E;&#x7C7B;
            DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
                        // deferredImportSelectors &#x8FD9;&#x91CC;&#x662F;true&#xFF0C;deferredImportSelectorHandler&#x5728;&#x521B;&#x5EFA;&#x7684;&#x65F6;&#x5019;&#x5C31;&#x4F1A;&#x521D;&#x59CB;&#x5316;deferredImportSelectors&#x5C5E;&#x6027;&#xFF0C;
                        // deferredImportSelectors&#x662F;&#x4E00;&#x4E2A;&#x96C6;&#x5408;&#xFF0C;&#x91CC;&#x9762;&#x5B58;&#x50A8;DeferredImportSelectorHolder&#x7C7B;&#x578B;
            if (this.deferredImportSelectors == null) {
                DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
                handler.register(holder);
                handler.processGroupImports();
            }
            else {
                this.deferredImportSelectors.add(holder);
            }
        }

1.2、deferredImportSelectorHandler.process 执行解析

        public void process() {
                        // &#x83B7;&#x53D6;&#x4E4B;&#x524D;&#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x8FC7;&#x7A0B;&#x4E2D;&#x6240;&#x6709;@Import&#x6CE8;&#x89E3;&#x5BFC;&#x5165;&#x7684;&#x5B9E;&#x73B0;DeferredImportSelector&#x63A5;&#x53E3;&#x7684;&#x7C7B;&#x7684;&#x6301;&#x6709;&#x8005;&#x7C7B;&#xFF0C;&#x6CE8;&#x610F;&#xFF1A;&#x662F;&#x7C7B;&#x7684;&#x6301;&#x6709;&#x8005;&#x7C7B;
            List<deferredimportselectorholder> deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;
            try {
                if (deferredImports != null) {
                                        // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;DeferredImportSelectorGroupingHandler&#x5BF9;&#x8C61;
                    DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
                                        // &#x5C06;deferredImports&#x96C6;&#x5408;&#x91CC;&#x9762;&#x7684;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#x6392;&#x5E8F;
                    deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
                                        // &#x5C06;&#x8981;&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#x904D;&#x5386;&#x6DFB;&#x52A0;&#x5230;DeferredImportSelectorGroupingHandler&#x5BF9;&#x8C61;&#x4E2D;&#xFF0C;&#x89C1;&#x6807;&#x9898;1.2.1
                    deferredImports.forEach(handler::register);
                                        // DeferredImportSelectorGroupingHandler &#x5F00;&#x59CB;&#x6267;&#x884C;&#x5BFC;&#x5165;&#xFF0C;&#x89C1;&#x8868;&#x683C;1.2.2
                    handler.processGroupImports();
                }
            }
            finally {
                                // &#x5728;&#x5BFC;&#x5165;&#x7C7B;&#x89E3;&#x6790;&#x5B8C;&#x6210;&#x540E;&#xFF0C;&#x5C06;deferredImportSelectors&#x91CD;&#x7F6E;&#xFF0C;&#x6E05;&#x7A7A;
                this.deferredImportSelectors = new ArrayList<>();
            }
        }
</deferredimportselectorholder>

在这之前,我们先讲解一下 DeferredImportSelector这个接口,他的大概结构是这个下面这样(删除了注释以及一些不重要方法), DeferredImportSelector这个接口中还有一个 Group接口, Group接口中还存在一个内部类 Entry

而我们后面要讲的和自动装配相关的,@Import导入的 AutoConfigurationImportSelector类,实现了这个 DeferredImportSelector接口,
AutoConfigurationImportSelector类的内部类 AutoConfigurationGroup也实现了 DeferredImportSelector接口中的 Group接口,另外一个内部类是 AutoConfigurationEntry
AutoConfigurationImportSelector类中的 getImportGroup方法返回的就是他的内部类 AutoConfigurationGroup

内部类 AutoConfigurationGroup有两个方法
process方法,用来执行 AutoConfigurationImportSelector,从spring.factory中获取所有的要自动装配的类,然后封装到内部类 AutoConfigurationEntry
selectImports方法,就是将 process方法解析出来的 AutoConfigurationEntry对象中的要自动装配的类逐个转换为 Entry类型,然后返回

Entry中有两个属性,其中一个 importClassName就是要导入的配置的全类名,会对这个类进行上文中相同的配置类解析过程

public interface DeferredImportSelector extends ImportSelector {
    default Class<? extends Group> getImportGroup() {
        return null;
    }
    interface Group {
        void process(AnnotationMetadata metadata, DeferredImportSelector selector);
        Iterable<entry> selectImports();
        class Entry {
            private final AnnotationMetadata metadata;
            private final String importClassName;
            public Entry(AnnotationMetadata metadata, String importClassName) {
                this.metadata = metadata;
                this.importClassName = importClassName;
            }
            public AnnotationMetadata getMetadata() {return this.metadata;}
            public String getImportClassName() {return this.importClassName;}
        }
    }
}

</entry>

debug进入注册方法

        public void register(DeferredImportSelectorHolder deferredImport) {
                        // &#x83B7;&#x53D6;DeferredImportSelectorHolder&#x4E2D;&#x7684;AutoConfigurationImportSelector&#x7684;AutoConfigurationGroup
            Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
                        // &#x7136;&#x540E;&#x5C06;AutoConfigurationGroup&#x5305;&#x88C5;&#x6210;DeferredImportSelectorGrouping
                        // &#x518D;&#x4EE5;DeferredImportSelectorHolder&#x6216;&#x8005;AutoConfigurationGroup&#x4E3A;key,&#x4EE5;DeferredImportSelectorGrouping&#x4E3A;&#x503C;&#x5B58;&#x5165;groupings&#x96C6;&#x5408;&#xFF0C;&#x8FD4;&#x56DE;&#x7684;&#x5C31;&#x662F;DeferredImportSelectorGrouping
            DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
                    (group != null ? group : deferredImport),
                    key -> new DeferredImportSelectorGrouping(createGroup(group)));
                        // &#x5728;&#x628A;DeferredImportSelectorHolder&#x52A0;&#x5165;DeferredImportSelectorGrouping
            grouping.add(deferredImport);
            this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                    deferredImport.getConfigurationClass());
        }
        public void processGroupImports() {
                        // &#x83B7;&#x53D6;&#x5230;&#x4E4B;&#x524D;&#x6240;&#x6709;&#x7684;grouping&#xFF0C;&#x904D;&#x5386;&#x6267;&#x884C;
            for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
                Predicate<string> exclusionFilter = grouping.getCandidateFilter();
                                // foreach &#x91CC;&#x9762;&#x7684;&#x903B;&#x8F91;&#x5C31;&#x662F;&#x6211;&#x4EEC;&#x524D;&#x9762;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x8FC7;&#x7A0B;&#xFF0C;&#x6211;&#x4EEC;&#x5C31;&#x4E0D;&#x518D;&#x770B;&#x4E86;&#xFF0C;&#x6700;&#x7EC8;&#x4F1A;&#x628A;&#x89E3;&#x6790;&#x51FA;&#x6765;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x5168;&#x90E8;&#x5B58;&#x5165;ConfigurationClassParser&#x7C7B;&#x4E2D;&#x7684;configurationClasses&#x96C6;&#x5408;&#x4E2D;
                                // &#x6211;&#x4EEC;&#x4E3B;&#x8981;&#x770B;getImports()&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;
                grouping.getImports().forEach(entry -> {
                    ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
                    try {
                        processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
                                Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
                                exclusionFilter, false);
                    }
                                        // &#x7701;&#x7565;&#x90E8;&#x5206;&#x65E0;&#x5F71;&#x54CD;&#x903B;&#x8F91;
                });
            }
        }
</string>

debug进入getImports这个方法

        public Iterable<group.entry> getImports() {
            for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                                // &#x6267;&#x884C;&#xFF0C;&#x83B7;&#x53D6;&#x5230;&#x6240;&#x6709;&#x914D;&#x7F6E;&#x5230;spring.factory&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x89C1;&#x6807;&#x9898;1.2.2.1
                this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
            }
                        // &#x5C06;&#x4E0A;&#x9762;&#x83B7;&#x53D6;&#x5230;&#x7684;&#x6240;&#x6709;&#x914D;&#x7F6E;&#x7C7B;&#x8FDB;&#x884C;&#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x4E3A;Entry&#xFF0C;&#x89C1;&#x6807;&#x9898;1.2.2.2
            return this.group.selectImports();
        }
</group.entry>
        public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
                        // &#x7701;&#x7565;&#x90E8;&#x5206;&#x65E0;&#x5F71;&#x54CD;&#x903B;&#x8F91;

                        // &#x8FD9;&#x4E00;&#x6B65;&#x91CC;&#x83B7;&#x53D6;&#x5230;&#x6240;&#x6709;&#x7684;spring.factory&#x914D;&#x7F6E;&#x7684;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x7C7B;&#xFF0C;&#x7136;&#x540E;&#x5305;&#x88C5;&#x5230;AutoConfigurationEntry&#x4E2D;&#xFF0C;&#x6838;&#x9500;&#x903B;&#x8F91;&#x4E00;&#x4F1A;debug&#x8981;&#x770B;
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
        }
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
                // &#x83B7;&#x53D6;&#x5230;&#x6240;&#x6709;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x96C6;&#x5408;
        List<string> configurations = getCandidateConfigurations(annotationMetadata, attributes);
                // &#x5220;&#x9664;&#x91CD;&#x590D;&#x7684;&#x96C6;&#x5408;
        configurations = removeDuplicates(configurations);
                // &#x83B7;&#x53D6;&#x8981;&#x6392;&#x9664;&#x7684;&#x914D;&#x7F6E;&#x7C7B;
        Set<string> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
                // &#x5220;&#x9664;&#x8981;&#x6392;&#x9664;&#x7684;&#x914D;&#x7F6E;&#x7C7B;
        configurations.removeAll(exclusions);
                // &#x8FC7;&#x6EE4;&#x6389;&#x4E0D;&#x7B26;&#x5408;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x6761;&#x4EF6;&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#xFF0C;&#x5176;&#x5B9E;&#x5C31;&#x83B7;&#x53D6;&#x5230;spring.factory&#x914D;&#x7F6E;&#x7684;&#x5B9E;&#x73B0;AutoConfigurationImportFilter&#x63A5;&#x53E3;&#x7684;&#x7C7B;&#xFF0C;&#x4E3B;&#x8981;&#x6709;OnBeanCondition&#xFF0C;OnClassCondition&#xFF0C;OnWebApplicationCondition&#x8FD9;&#x4E09;&#x4E2A;
        configurations = getConfigurationClassFilter().filter(configurations);
                // &#x53D1;&#x9001;&#x81EA;&#x52A8;&#x88C5;&#x914D;&#x65F6;&#x95F4;
        fireAutoConfigurationImportEvents(configurations, exclusions);
                // &#x5C06;&#x914D;&#x7F6E;&#x7C7B;&#x96C6;&#x5408;&#x5305;&#x88C5;&#x5230;AutoConfigurationEntry&#x5BF9;&#x8C61;&#x4E2D;
        return new AutoConfigurationEntry(configurations, exclusions);
    }
</string></string>
        public Iterable<entry> selectImports() {
            if (this.autoConfigurationEntries.isEmpty()) {
                return Collections.emptyList();
            }
            Set<string> allExclusions = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            Set<string> processedConfigurations = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
                    .collect(Collectors.toCollection(LinkedHashSet::new));
            processedConfigurations.removeAll(allExclusions);

            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
                    .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
                    .collect(Collectors.toList());
        }
</string></string></entry>

debug进入,这里面传入了所有解析出来的配置类

    public void loadBeanDefinitions(Set<configurationclass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
                        // &#x904D;&#x5386;&#x914D;&#x7F6E;&#x7C7B;&#x8FDB;&#x884C;&#x89E3;&#x6790;
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }
</configurationclass>

看一下整体的解析流程,每一个解析过程就不看了,这里面的流程其实是Spring的流程

    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;
        }

                // &#x5224;&#x65AD;&#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x5426;&#x7531;&#x5176;&#x4ED6;&#x914D;&#x7F6E;&#x7C7B;&#x5BFC;&#x5165;&#x7684;&#xFF0C;&#x800C;&#x4E0D;&#x662F;@Import&#x6CE8;&#x89E3;&#x5BFC;&#x5165;&#x7684;
        if (configClass.isImported()) {
                        // &#x5C06;&#x8FD9;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;&#x672C;&#x8EAB;&#x89E3;&#x6790;&#x6210;&#x4E00;&#x4E2A;beanDefinition
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
                // &#x5224;&#x65AD;&#x8FD9;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;&#x662F;&#x4E0D;&#x662F;&#x6709;@Bean&#x6CE8;&#x89E3;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x5982;&#x679C;&#x6709;&#xFF0C;&#x5219;&#x5C06;@Bean&#x6CE8;&#x89E3;&#x8FD4;&#x56DE;&#x7684;&#x7ED3;&#x679C;&#x89E3;&#x6790;&#x6210;&#x4E00;&#x4E2A;BeanDefinition
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }

                // &#x83B7;&#x53D6;&#x8FD9;&#x4E2A;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;@ImportResources&#x6216;&#x8005;@ImportResource&#x5BFC;&#x5165;&#x7684;&#x7C7B;&#xFF0C;&#x8FD9;&#x4E9B;&#x7C7B;&#x89E3;&#x6790;&#x6210;&#x4E00;&#x4E2A;BeanDefinition
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
                //  &#x5C06;&#x524D;&#x9762;@Import&#x6CE8;&#x89E3;&#x5BFC;&#x5165;&#x7684;&#x5B9E;&#x73B0;&#x4E86;ImportBeanDefinitionRegistrar&#x7684;&#x63A5;&#x53E3;&#x7684;&#x7C7B;&#x89E3;&#x6790;&#x6210;&#x4E00;&#x4E2A;BeanDefinition
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

至此,整个Springboot的自动装配流程解析完成,下一节对整个流程做一个总结

Original: https://www.cnblogs.com/junzisi/p/15553604.html
Author: 君子思
Title: 10、SpringBoot 启动 刷新应用上下文 自动装配解析(二)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607565/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 多线程与高并发(一)—— 自顶向下理解Synchronized实现原理

    一、 什么是锁? 在多线程中,多个线程同时对某一个资源进行访问,容易出现数据不一致问题,为保证并发安全,通常会采取线程互斥的手段对线程进行访问限制,这个互斥的手段就可以称为锁。锁的…

    Java 2023年6月9日
    064
  • 如何成为一名JAVAEE软件工程师?(前言)

    笔者将会整理出一整套成为一个JAVAEE工程师的学习路线和资料。欢迎同行和网友们订阅或指正。不定期更新。 笔者在软件工作做了7年java开发,开发过ERP,CRM等应用系统并担任过…

    Java 2023年6月9日
    077
  • 「免费开源」基于Vue和Quasar的前端SPA项目crudapi后台管理系统实战之EXCEL数据导出(十三)

    基于Vue和Quasar的前端SPA项目实战之数据导出(十三) 回顾 通过之前一篇文章基于Vue和Quasar的前端SPA项目实战之数据导入(九)的介绍,通过配置的方式可以零代码实…

    Java 2023年6月6日
    087
  • 程序员工作中的理性与感性活动及所需的技能素养

    程序员工作中的理性与感性活动及所需的技能素养。 真的是被”严酷的工作”拷打出来的人啊! 理性与感性活动 梳理和熟悉业务。需要方法和细心。请教、询问、交谈、文…

    Java 2023年6月9日
    0110
  • 老杜带你学Ajax,轻松掌握ajax底层实现原理

    课程导读 原生的ajax虽然在实际开发中很少编写,但如果想将js高级框架底层学明白,那ajax的原理是必须要求精通的。 本套ajax视频对ajax底层实现原理讲解非常透彻,对aja…

    Java 2023年6月9日
    0107
  • Linux下搭建maven(maven3.6+nexus3.2)私服

    准备maven和nexus安装包,nexus安装包好像要FQ,不然下载不到! 链接:https://pan.baidu.com/s/1bVMadGoTAK9pSLW6yBNOCg提…

    Java 2023年6月8日
    091
  • 从零开始实现lmax-Disruptor队列(六)Disruptor 解决伪共享、消费者优雅停止实现原理解析

    在v5版本的MyDisruptor实现DSL风格的API后。按照计划,v6版本的MyDisruptor作为最后一个版本,需要对MyDisruptor进行最终的一些细节优化。v6版本…

    Java 2023年6月8日
    073
  • Java的发展史

    在当时,客户端编程所迈出的最重要的一步就是 插件(plug-in) 的开发。通过这种方式,用户可以下载一段代码,并将其插入到浏览器中适当的位置,以此来为浏览器添加新的功能。 插件又…

    Java 2023年5月29日
    075
  • 记一次SQL优化

    昨天(2022-7-22)上线了我的一个功能,测试环境数据量较小,问题不大,但是上生产之后,直接卡死了,然后就开始了这么一次SQL优化,这里记录一下。 不太方便透露公司的表结构,这…

    Java 2023年6月5日
    064
  • 船舱订票系统测试

    package com.dong.mytest.demo.other.yan; import java.util.ArrayList; import java.util.HashM…

    Java 2023年6月5日
    089
  • 信息系统项目管理师计划

    报名地址:https://bm.ruankao.org.cn/sign/welcome#test=2 课程内容 视频时长 计划开始时间 实际开始时间 完成时间 信息系统项目管理基础…

    Java 2023年6月9日
    070
  • SpringCloud系列之API网关(Gateway)服务Zuul

    1、什么是API网关 API网关是所有请求的入口,承载了所有的流量,API Gateway是一个门户一样,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的Facet模式很像。…

    Java 2023年5月30日
    078
  • 观察者模式,无需多线程完成数据监听

    大家好,我们今天来了解一个新的设计模式—— 观察者模式。 观察者模式的思路很简单,它被广泛地用在各种数据监控上。很多时候我们希望监听某个数据的变化,希望一旦获悉它的变化之后立即采取…

    Java 2023年5月30日
    094
  • Spring为list集合和map集合类型赋值

    1.通过List标签在property标签中直接进行赋值 2.通过配置一个list集合类型的bean,需要使用util的约束(直接写,可以自动导入) 然后再通过id引用该list集…

    Java 2023年6月16日
    095
  • SeataAT模式入门

    Seata架构 Seata将分布式事务理解为一个全局事务,它由若干个分支事务组成,一个分支事务就是一个满足ACID的本地事务。 Seata架构中有三个角色:TC (Transact…

    Java 2023年6月9日
    0216
  • VMware 虚拟机安装(包含秘钥)

    1.下载 VMware官网地址:https://www.vmware.com/cn/products/workstation-pro.html (1)首先进入官网 点击下载 (2)…

    Java 2023年6月5日
    092
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球