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

debug进入 refreshContext方法

    private void refreshContext(ConfigurableApplicationContext context) {
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
                // 进入刷新方法
        refresh((ApplicationContext) context);
    }
    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
                // 进入重载刷新方法
        refresh((ConfigurableApplicationContext) applicationContext);
    }
    protected void refresh(ConfigurableApplicationContext applicationContext) {
                // 调用上下文自己的刷新方法
        applicationContext.refresh();
    }
        public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.

                                // beanFactory后处理,向工厂中注入WebApplicationContextServletContextAwareProcessor,这一步我们不用太关心
                postProcessBeanFactory(beanFactory);

                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                // Invoke factory processors registered as beans in the context.

                                // 回调所有的 BeanFactoryPostProcessor,其中自动装配就是在该步完成,重点要关心的
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.

                                // 创建并启动 Tomcat 服务器,就是在该步完成,重点要关心的
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
                contextRefresh.end();
            }
        }
    }

debug进入 invokeBeanFactoryPostProcessors方法

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
                // 调用后置处理注册器工具类,将获取到到的 BeanFactoryPostProcessor 实例化并调用
        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 (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors方法逻辑很复杂,这个和Spring一样,这里我们只看和自动装配有关的那个 BeanFactoryPostProcessor

    public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<beanfactorypostprocessor> beanFactoryPostProcessors) {
                // &#x7701;&#x7565;&#x4E0D;&#x91CD;&#x8981;&#x903B;&#x8F91;---

        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
                // &#x5728;&#x5448;&#x73B0;&#x7684;&#x90E8;&#x5206;&#x4EE3;&#x7801;&#x91CC;&#x4E0A;&#x9762;&#x90A3;&#x90E8;&#x5206;&#x4EE3;&#x7801;&#x5C31;&#x662F;&#x83B7;&#x53D6;&#x6240;&#x6709;BeanDefinitionRegistryPostProcessor&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x7136;&#x540E;&#x8C03;&#x7528;
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();

                // &#x7701;&#x7565;&#x4E0D;&#x91CD;&#x8981;&#x903B;&#x8F91;---
        }
</beanfactorypostprocessor>

然后遍历所有的 BeanDefinitionRegistryPostProcessor的实现类
我们在前文创建 应用上下文时说过,在创建过程中想上下文 beanFactory中注册了一个 ConfigurationClassPostProcessor,这个类也实现了 BeanDefinitionRegistryPostProcessor
ConfigurationClassPostProcessor也是我们重点关注的类,自动装配就和他有关系,我们只需要debug他就可以了

    private static void invokeBeanDefinitionRegistryPostProcessors(
            Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

        for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
            StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
                    .tag("postProcessor", postProcessor::toString);
                        // &#x627E;&#x5230;ConfigurationClassPostProcessor&#x7136;&#x540E;&#x6267;&#x884C;
            postProcessor.postProcessBeanDefinitionRegistry(registry);
            postProcessBeanDefRegistry.end();
        }
    }

进入 ConfigurationClassPostProcessor

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
                // &#x7701;&#x7565;&#x4E0D;&#x91CD;&#x8981;&#x4EE3;&#x7801; ......

                // ConfigurationClassPostProcessor&#x89E3;&#x6790;&#x7684;&#x6838;&#x5FC3;&#x65B9;&#x6CD5;
        processConfigBeanDefinitions(registry);
    }

然后我们进入 ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法,

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<beandefinitionholder> configCandidates = new ArrayList<>();
                // &#x83B7;&#x53D6;&#x5F53;&#x524D;beanFactory&#x4E2D;&#x7684;&#x6240;&#x6709;beanName
        String[] candidateNames = registry.getBeanDefinitionNames();

                // &#x904D;&#x5386;&#x5F53;&#x524D;beanFactory&#x4E2D;&#x7684;&#x6240;&#x6709;beanName&#xFF0C;&#x56E0;&#x4E3A;&#x8FD8;&#x51FA;&#x53BB;&#x56DE;&#x8C03;beanFactroyPostProcessor&#x9636;&#x6BB5;&#xFF0C;&#x5DE5;&#x5382;&#x4E2D;&#x7684;beanName&#x53EA;&#x6709;&#x51E0;&#x4E2A;
        for (String beanName : candidateNames) {
                        // &#x83B7;&#x53D6;beanName&#x5BF9;&#x5E94;&#x7684;BeanDefinition
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                        // CONFIGURATION_CLASS_ATTRIBUTE = "org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass"
                        // &#x5982;&#x679C;BeanDefinition &#x4E2D;&#x6709; CONFIGURATION_CLASS_ATTRIBUTE&#x5C5E;&#x6027;&#xFF0C;&#x8BF4;&#x660E;&#x8FD9;&#x4E2A;bean&#x5DF2;&#x7ECF;&#x88AB;&#x89E3;&#x6790;&#x8FC7;&#x4E86;&#xFF0C;&#x4E0D;&#x9700;&#x8981;&#x518D;&#x89E3;&#x6790;
            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
                        //  &#x5982;&#x679C;BeanDefinition &#x4E2D;&#x6CA1;&#x6709; CONFIGURATION_CLASS_ATTRIBUTE&#x5C5E;&#x6027;&#xFF0C;&#x5219;&#x9700;&#x8981;&#x5224;&#x65AD;&#x662F;&#x5426;&#x9700;&#x8981;&#x89E3;&#x6790;
                        // &#x5224;&#x65AD;&#x903B;&#x8F91;&#x5C31;&#x4E0D;&#x770B;&#x4E86;&#xFF0C;&#x5728;&#x8FD9;&#x91CC;&#x76F4;&#x63A5;&#x5199;&#xFF0C;&#x5F53;&#x7C7B;&#x4E0A;&#x9762;&#x6807;&#x6CE8;&#x4E86;@Configuration/@Component/@ComponentScan/@Import/@ImportResource&#x7B49;&#x6CE8;&#x89E3;&#xFF0C;&#x5C31;&#x662F;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x9700;&#x8981;&#x8FDB;&#x884C;&#x540E;&#x9762;&#x7684;&#x89E3;&#x6790;
                        // &#x8FD9;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;&#x7684;&#x65B9;&#x6CD5;&#x540E;&#x9762;&#x8FD8;&#x4F1A;&#x7528;&#x5230;
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        // Return immediately if no @Configuration classes were found
                // &#x5224;&#x65AD;&#x662F;&#x5426;&#x4E3A;&#x7A7A;&#xFF0C;&#x5982;&#x679C;&#x4E3A;&#x7A7A;&#x5219;&#x8BF4;&#x660E;&#x6CA1;&#x6709;&#x9700;&#x8981;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x76F4;&#x63A5;&#x8FD4;&#x56DE;&#xFF0C;&#x4E00;&#x822C;&#x7B2C;&#x4E00;&#x6B21;&#x542F;&#x52A8;&#xFF0C;&#x6211;&#x4EEC;&#x80FD;&#x62FF;&#x5230;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x5C31;&#x662F;&#x6211;&#x4EEC;&#x7684;&#x542F;&#x52A8;&#x7C7B;&#xFF0C;
        if (configCandidates.isEmpty()) {
            return;
        }

        // Sort by previously determined @Order value, if applicable
                // &#x5BF9;&#x9700;&#x8981;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x8FDB;&#x884C;&#x6392;&#x5E8F;
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return Integer.compare(i1, i2);
        });

        // Detect any custom bean name generation strategy supplied through the enclosing application context
        SingletonBeanRegistry sbr = null;

                // registry&#x5B9E;&#x73B0;&#x4E86;SingletonBeanRegistry&#xFF0C;&#x6B64;&#x5904;&#x4E3A;true
        if (registry instanceof SingletonBeanRegistry) {
                        // &#x5C06;registry&#x5F3A;&#x8F6C;&#x4E3A;SingletonBeanRegistry
            sbr = (SingletonBeanRegistry) registry;

                        // &#x9ED8;&#x8BA4;&#x4E3A;false&#xFF0C;&#x6B64;&#x5904;&#x4E5F;&#x6210;&#x7ACB;
            if (!this.localBeanNameGeneratorSet) {
                                // &#x4ECE;&#x5DE5;&#x5382;&#x4E2D;&#x83B7;&#x53D6;org.springframework.context.annotation.internalConfigurationBeanNameGenerator&#xFF0C;&#x5BF9;&#x5E94;&#x7684;bean
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                        AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
                                // &#x7B2C;&#x4E00;&#x6B21;&#x521B;&#x5EFA;&#x5E94;&#x7528;&#x4E0A;&#x4E0B;&#x6587;&#xFF0C;&#x4E3A;&#x7A7A;&#xFF0C;
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }

                // &#x5B9E;&#x4F8B;&#x5316;&#x65F6;&#x5C06;&#x4E0A;&#x4E0B;&#x6587;&#x4E2D;&#x7684;&#x73AF;&#x5883;&#x8D4B;&#x503C;&#x7ED9;&#x4E86;&#x5F53;&#x524D;&#x5BF9;&#x8C61;&#xFF0C;&#x6B64;&#x5904;&#x4E0D;&#x4E3A;&#x7A7A;
        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }

        // Parse each @Configuration class
                // &#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x5668;&#xFF0C;&#x4E0D;&#x8981;&#x88AB;&#x6B64;&#x5904;&#x7684;&#x82F1;&#x6587;&#x8BEF;&#x5BFC;&#x4E86;&#xFF0C;&#x8FD9;&#x4E2A;&#x89E3;&#x6790;&#x5668;&#x53EF;&#x4EE5;&#x89E3;&#x6790;@Component&#xFF0C;@PropertySources&#xFF0C;@ComponentScans&#xFF0C;@Import&#xFF0C;@ImportResource&#xFF0C;@Bean&#x8FD9;&#x4E9B;&#x6CE8;&#x89E3;
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

                // &#x5C06;&#x5F85;&#x89E3;&#x6790;&#x7684;BeanDefinitionHolder&#x5B58;&#x5165;candidates&#x96C6;&#x5408;&#xFF0C;&#x540E;&#x9762;&#x904D;&#x5386;&#x89E3;&#x6790;
        Set<beandefinitionholder> candidates = new LinkedHashSet<>(configCandidates);
                // &#x6536;&#x96C6;&#x5DF2;&#x7ECF;&#x89E3;&#x6790;&#x8FC7;&#x7684;&#x7C7B;
        Set<configurationclass> alreadyParsed = new HashSet<>(configCandidates.size());
                // &#x5FAA;&#x73AF;&#x89E3;&#x6790;
        do {
            StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
                        // &#x5F00;&#x59CB;&#x89E3;&#x6790; &#x4E0A;&#x9762;&#x5B58;&#x5165;candidates&#x96C6;&#x5408;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x6838;&#x5FC3;&#x903B;&#x8F91;
            parser.parse(candidates);
                        // &#x904D;&#x5386;&#x6240;&#x6709;&#x89E3;&#x6790;&#x51FA;&#x6765;&#x7684;&#x7C7B;&#xFF0C;&#x68C0;&#x67E5;&#x6807;&#x6CE8;&#x6709;@Configuration&#x6CE8;&#x89E3;&#x4E14;proxyBeanMethods&#x5C5E;&#x6027;=true&#x7684;&#x7C7B;&#x4E0E;&#x5176;@bean&#x6807;&#x6CE8;&#x7684;&#x65B9;&#x6CD5;&#x662F;&#x4E0D;&#x662F;fianl&#x5173;&#x952E;&#x5B57;&#x4FEE;&#x9970;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x5219;&#x62A5;&#x9519;
            parser.validate();

                        // &#x83B7;&#x53D6;&#x6240;&#x6709;&#x7684;&#x89E3;&#x6790;&#x51FA;&#x6765;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x5B58;&#x5165;configClasses&#x96C6;&#x5408;
            Set<configurationclass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                        //&#x5220;&#x9664;&#x6389;&#x914D;&#x7F6E;&#x7C7B;&#x96C6;&#x5408;&#x4E2D;&#x5DF2;&#x7ECF;&#x89E3;&#x6790;&#x8FC7;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x9632;&#x6B62;&#x91CD;&#x590D;&#x89E3;&#x6790;
            configClasses.removeAll(alreadyParsed);

            // Read the model and create bean definitions based on its content

                        // &#x5982;&#x679C;&#x8BFB;&#x53D6;&#x5668;&#x4E3A;&#x7A7A;&#xFF0C;&#x5219;&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#xFF0C;&#x914D;&#x7F6E;&#x7C7B;bean&#x5B9A;&#x4E49;&#x4FE1;&#x606F;&#x8BFB;&#x53D6;&#x5668;&#xFF0C;&#x8BE5;&#x8BFB;&#x53D6;&#x5668;&#x4E13;&#x95E8;&#x5C06;&#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x6210;BeanDefinition
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
                        // &#x5C06;&#x914D;&#x7F6E;&#x7C7B;&#x89E3;&#x6790;&#x4E3A;beanDefinition&#xFF0C;&#x6838;&#x5FC3;&#x903B;&#x8F91;
            this.reader.loadBeanDefinitions(configClasses);

                        // &#x5C06;&#x89E3;&#x6790;&#x8FC7;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x52A0;&#x5165;&#x5DF2;&#x89E3;&#x6790;&#x96C6;&#x5408;
            alreadyParsed.addAll(configClasses);
            processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

                        // &#x6E05;&#x7A7A;&#x5F85;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;
            candidates.clear();
                        // &#x5982;&#x679C;&#x89E3;&#x6790;&#x540E;&#x7684; BeanDefinition &#x7684;&#x603B;&#x6570; > &#x5927;&#x4E8E;&#x89E3;&#x6790;&#x524D;&#x7684;  BeanDefinition &#x7684;&#x603B;&#x6570;&#xFF0C;&#x5219;&#x9700;&#x8981;&#x68C0;&#x67E5;&#x65B0;&#x589E;&#x7684;bean&#x4E2D;&#x662F;&#x5426;&#x6709;&#x914D;&#x7F6E;&#x7C7B;
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                                // &#x83B7;&#x53D6;&#x6240;&#x6709;&#x7684;beanName
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                                // &#x83B7;&#x53D6;&#x6240;&#x6709;&#x89E3;&#x6790;&#x4E4B;&#x524D;&#x7684;beanName
                Set<string> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                                // &#x6536;&#x96C6;&#x6240;&#x6709;&#x5DF2;&#x89E3;&#x6790;&#x7684;beanName
                Set<string> alreadyParsedClasses = new HashSet<>();
                for (ConfigurationClass configurationClass : alreadyParsed) {
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                }
                                // &#x904D;&#x5386;&#x6240;&#x6709;&#x7684;beanName,&#x5982;&#x679C;&#x4ED6;&#x5728;&#x89E3;&#x6790;&#x4E4B;&#x524D;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x5219;&#x83B7;&#x53D6;&#x4ED6;&#x7684;&#x4ED6;BeanDefinition
                for (String candidateName : newCandidateNames) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                                                // &#x7136;&#x540E;&#x68C0;&#x67E5;&#xFF0C;&#x8FD9;&#x4E2A;&#x7C7B;&#x662F;&#x4E0D;&#x662F;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x5E76;&#x4E14;&#x6CA1;&#x6709;&#x89E3;&#x6790;&#x8FC7;&#xFF0C;&#x5982;&#x679C;&#x662F;&#xFF0C;&#x5219;&#x52A0;&#x5165;&#x5F85;&#x89E3;&#x6790;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                                /// &#x540C;&#x65F6;&#x5C06;&#x89E3;&#x6790;&#x524D;&#x6240;&#x6709;&#x914D;&#x7F6E;&#x7C7B;&#x66F4;&#x65B0;
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());

        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
        if (sbr != null && !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();
        }
    }
</string></string></configurationclass></configurationclass></beandefinitionholder></beandefinitionholder>

上面这段解析流程中,最重要的是 parser.parse(candidates);this.reader.loadBeanDefinitions(configClasses);这两行代码
parser.parse(candidates);代表的是将待解析的配置类中的类解析出来,而自动装配的逻辑也在其中
this.reader.loadBeanDefinitions(configClasses);代表的时候将解析出来的类,转化为 BeanDefinition
我们下篇文章再分析

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

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

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

(0)

大家都在看

  • javaNIO:选择器–理论 Selector

    选择器 最后,我们探索一下选择器,选择器Selector是nio最重要的一个特性。由于选择器内容比较多,所以本篇先偏理论地讲一下,后一篇讲代码,文章也没有什么概括、总结的,写到哪儿…

    Java 2023年5月29日
    066
  • 01-RocketMQ介绍

    一、MQ介绍 1、什么是MQ?为什么要用MQ? MQ:MessageQueue,消息队列。 队列,是一种FIFO 先进先出的数据结构。消息由生产者发送到MQ进行排队,然后按原来的顺…

    Java 2023年6月7日
    0126
  • Linux 学习笔记(一)

    Linux学习笔记(一) 1.1Linux的文件权限 Linux一般将文件的可读写身份分为三个类别:拥有者(owner)、所属群组(group)、其他人(others),并且三种身…

    Java 2023年6月7日
    069
  • 学生成绩管理系统【c】

    include Original: https://www.cnblogs.com/java20130723/p/3211444.htmlAuthor: 程序流程图Title: 学…

    Java 2023年5月29日
    066
  • 汇总数据库信息的存储过程

    问题: mysql日常开发过程中,数据库、表的很多信息分散在不同的工具和不同的界面中,来回切换查找非常麻烦。 解决方式: 基于这个问题,写了一个存储过程,将这些日常需要的信息集合在…

    Java 2023年6月9日
    078
  • 关于Springboot配置多数据源,这篇笔记太详细了!

    关于springboot配置多数据源,整理了这篇笔记,分享给有需要的小伙伴们,视频看的动力节点王鹤老师讲的springboot 目录结构 1. DataSourceConfigur…

    Java 2023年6月7日
    072
  • java学习笔记day1

    一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。 对象:对象是类的一个实例,有状态和行为。例如…

    Java 2023年6月5日
    068
  • 为什么不建议使用自定义Object作为HashMap的key?

    此前部门内的一个线上系统上线后内存一路飙高、一段时间后直接占满。协助开发人员去分析定位,发现内存中某个Object的量远远超出了预期的范围,很明显出现内存泄漏了。 结合代码分析发现…

    Java 2023年6月7日
    068
  • input框设置禁用状态

    input设置为不可编辑的状态(三种方法,可自行选择) 1. disabled 属性规定应该禁用 input 元素,被禁用的 input 元素,不可编辑,不可复制,不可选择,不能接…

    Java 2023年6月5日
    067
  • JWT token验证后,通过 ThreadLocal 进行传值

    JWT token验证后,通过 ThreadLocal 进行传值,在服务层直接使用 Threadlocal 获取当前用户,的Id、姓名,进行行为记录 定义一个用户实体类 Sessi…

    Java 2023年6月13日
    055
  • 巧用异或

    异或有以下规律 一般的交换方式, 利用临时变量: a = 1 b = 2 temp = a a = b b = temp 但你也可以使用异或的方法交换: a = 1 b = 2 a…

    Java 2023年6月7日
    0118
  • Spring Tool 历史版本下载

    参考资料 说在前面 历史版本下载 规律 参考资料 Spring Tool Suit3下载地址 说在前面 官方目前只提供最新版本的 Spring Tool 4下载,并没有提供历史版本…

    Java 2023年6月9日
    071
  • Redis 安装与使用

    NoSQL 1. 定义 NoSQL(Not Only SQL)即不仅仅是 SQL,泛指非关系型的数据库 2. 为什么使用 NoSQL? 传统关系数据库在应付动态网站、特别是超大规模…

    Java 2023年6月8日
    077
  • 安卓开发入门(一)开发环境搭建

    开发工具 基本上就一个选项:Android Studio,从官网下载最新版版即可。 我下载时是2020.3.1 for Windows 64-bit。 官网地址:https://d…

    Java 2023年6月5日
    081
  • 微服务SpringCloud之服务网关zuul一

    前面学习了Eureka、Feign、Hystrix、Config,本篇来学习下API网关zuul。在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的u…

    Java 2023年5月30日
    092
  • Golang简介

    一、Golang的优势 1.部署简单: (1)可直接编译成机器码。 (2)不依赖其他库,最终生成的可执行程序是静态的可执行文件。 (3)直接运行,即可部署。 2.静态类型语言,相比…

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