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)

大家都在看

  • go本地文件的页面展示及删除功能

    新建控制器OperLogFileController 文件的页面展示功能:页面展示的文件名不可以有后缀名 //文件列表展示 func (c *OperLogFileControll…

    Java 2023年6月13日
    083
  • Effective Java 第三版——75. 在详细信息中包含失败捕获信息

    Tips书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code注意,书中的有些代码里方法是基于Java 9…

    Java 2023年5月29日
    089
  • 抽象类

    抽象类 当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract来修饰该类就是抽象类。 * 即:父类方法不确定性的问题 * =…

    Java 2023年6月5日
    089
  • Spring框架下的 “接口调用、MVC请求” 调用参数、返回值、耗时信息输出

    主要拦截前端或后天的请求,打印请求方法参数、返回值、耗时、异常的日志。方便开发调试,能很快定位到问题出现在哪个方法中。 前端请求拦截,mvc的拦截器 1 import java.u…

    Java 2023年5月30日
    0100
  • spring整合activemq发送MQ消息[queue模式]实例

    queue类型消息 pom依赖 junit junit 4.11 test org.apache.activemq activemq-all 5.11.1 org.springfr…

    Java 2023年5月30日
    090
  • 一次编程小练习:根据流量计数动态选择不同的策略

    持续优化一个程序的过程,也是编程技艺提升和编程的乐趣所在。 在实际应用中, 往往会承载两种不同的流量。一种是日常流量,比较平稳且持续;一种是极端流量,比较尖锐且短暂。应对这种情况,…

    Java 2023年6月9日
    079
  • 如何使用 RSA 加密 JWT

    <dependency> <groupid>com.nimbusds</groupid> <artifactid>nimbus-jo…

    Java 2023年6月7日
    098
  • Vue前端压缩图片

    一、在组件包下新建compressImage.js 二、在所需页面引入compressImage.js 三、使用方法 四、拿到压缩后的二进制文件该怎样发送给后台呢?(我后台用的是 …

    Java 2023年6月9日
    076
  • 短信接口防盗刷解决方案

    在Web开发中,总有一些接口需要暴露在用户认证前访问,短信发送接口特别是短信验证码注册接口便是其中典型的一类,这类接口具有如下特点: 流量在用户认证之前 流量在用户认证之前,意味着…

    Java 2023年6月6日
    098
  • Spring(十五):Spring整合MyBatis的两种方式

    在学习之前,我们先了解一个网站mybatis-spring,这是mybatis-spring整合的官方文档,里面有详细的教程,网址如下: https://mybatis.org/s…

    Java 2023年6月15日
    0107
  • java的6种单例模式

    第一种:饿汉式:当第一次访问这个对象的时候就向没吃过饭一样,类进行全部加载进去缺点:太消耗内存,全部加载不一定都会使用,产生垃圾优点:没有加锁,速度快 第二种:懒汉式(线程不安全)…

    Java 2023年6月9日
    072
  • node.js 运行vue项目

    (1)安装node.js,按照自己使用的系统情况选择下载包,我用的windows系统,所以选择了第一个 下载地址可以到官网:https://nodejs.org/en/downlo…

    Java 2023年6月5日
    092
  • 面试官:你说你精通Redis,你看过持久化的配置吗?

    前边我们已经介绍了 Redis 五种数据类型的命令与 配置文件的基本配置,今天让我们从理论和配置两个层面来揭开 Redis持久化的神秘面纱。 所谓持久化可以简单理解为将内存中的数据…

    Java 2023年6月5日
    077
  • 高司令 老骥伏枥,志在千里的 Java 之父

    1994年底,互联网的蓬勃发展给了 Oak 机会:James Gosling 参加了在硅谷召开的”技术、教育和设计大会”。他报着试一试的心情向与会者演示了 …

    Java 2023年5月29日
    085
  • Java学习 (23) 对象篇(03)封装&继承&多态

    我们程序设计要追求”高内聚,低耦合” 高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉 低耦合:仅暴露少量的方法给外部使用 通常,应禁止直接访问一个…

    Java 2023年6月8日
    0158
  • Spring 源码(18)Spring IOC 容器的创建总结

    Spring IOC Bean对象的创建总结 根据前面的介绍,可以进行Spring IOC容器创建Bean的总结: 调用构造函数启动,调用过程中父类会忽略调用三个 Aware接口,…

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