SpringBoot启动流程分析5--run方法之prepareContext()方法

从零到一:手把手教你用DJI E-Port套件为M350 RTK开发第三方负载(PSDK V3实战) 本文详细介绍了如何使用DJI E-Port套件为M350 RTK开发第三方负载,涵盖硬件配置、开发环境搭建及实战应用。通过PSDK V3开发套件,开发者可以高效实现负载与无人机的通信,适用于电力巡检等工业场景,提升开发效率与系统稳定性。 阅读详情

SpringBoot启动流程分析5–run方法之prepareContext()方法

一、概述

源码基于SpringBoot 2.7.xx版本

1.1 简介

准备应用上下文方法主要做了以下几件事:

  1. 设置ApplicationContext应用上下文环境对象
  2. 执行ApplicationContext后置处理
  3. 执行ApplicationContext初始化器
  4. 发布ApplicationContext已初始化事件
  5. 添加Bean工厂的后置处理器
  6. 加载 启动类 到Spring应用上下文BeanDefinitionMap中,为后面的spring进行自动化配置做好准备
  7. 发布ApplicationContext已准备完毕事件

二、详解

2.1 准备应用上下文

public class SpringApplication {

    private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
                                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                                ApplicationArguments applicationArguments, Banner printedBanner) {
        // 设置ApplicationContext应用上下文环境对象
        context.setEnvironment(environment);
        // 执行ApplicationContext后置处理
        postProcessApplicationContext(context);
        // 执行ApplicationContext初始化器
        // 即最开始加载的ApplicationContextInitializer中的initialize方法,向context中添加BeanFactoryPostProcessor、监听器等
        applyInitializers(context);
        // 发布ApplicationContext已初始化事件
        listeners.contextPrepared(context);
        // 执行关闭BootstrapContextCloseEvent类型的监听器
        bootstrapContext.close(context);
        // 开启日志功能
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 将main函数中的args参数封装成单例Bean,注册进容器
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            // 将 printedBanner 也封装成单例,注册进容器
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
            // 设置bean之间的循环引用,默认是为 false
            ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
            if (beanFactory instanceof DefaultListableBeanFactory) {
                // 下面这个是是否允许设置相同的bean名称,但是两个bean的定义不同,来让后者定义的bean覆盖前者。默认是允许的,但是这里设置了不允许
                ((DefaultListableBeanFactory) beanFactory)
                        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
            }
        }
        // 如果是延迟加载,就是getBean的时候才进行加载,那么就设置对应的lazy工厂后置处理器,默认是false
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // 添加Bean工厂的后置处理器
        context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 加载启动类到Spring应用上下文BeanDefinitionMap中,为后面的spring进行自动化配置做好准备
        load(context, sources.toArray(new Object[0]));
        // 发布ApplicationContext已准备完毕事件
        listeners.contextLoaded(context);
    }
}

2.2 加载启动类

public class SpringApplication {

    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        // 创建 BeanDefinitionLoader 
        BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }

    private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
        // 这里将我们前文创建的应用上下文强转为BeanDefinitionRegistry,他们之间是有继承关系的。
        // BeanDefinitionRegistry定义了很重要的方法registerBeanDefinition(),该方法将BeanDefinition注册进DefaultListableBeanFactory
        // 容器的beanDefinitionMap中。
        if (context instanceof BeanDefinitionRegistry) {
            return (BeanDefinitionRegistry) context;
        }
        if (context instanceof AbstractApplicationContext) {
            return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
        }
        throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
    }
}

2.2.1 createBeanDefinitionLoader()

public class SpringApplication {

    protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
        return new BeanDefinitionLoader(registry, sources);
    }
}

class BeanDefinitionLoader {

    private final Object[] sources;

    private final AnnotatedBeanDefinitionReader annotatedReader;

    private final AbstractBeanDefinitionReader xmlReader;

    private final BeanDefinitionReader groovyReader;

    private final ClassPathBeanDefinitionScanner scanner;

    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
        Assert.notNull(registry, "Registry must not be null");
        Assert.notEmpty(sources, "Sources must not be empty");
        this.sources = sources;
        // 注解形式的Bean定义读取器 比如:@Configuration @Bean @Controller @Service @Component等等
        this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
        // XML形式的Bean定义读取器
        this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
        this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
        // 类路径扫描器
        this.scanner = new ClassPathBeanDefinitionScanner(registry);
        // 扫描器添加排除过滤器
        this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
    }

    void load() {
        for (Object source : this.sources) {
            load(source);
        }
    }

    private void load(Object source) {
        Assert.notNull(source, "Source must not be null");
        // 从Class加载
        if (source instanceof Class<?>) {
            load((Class<?>) source);
            return;
        }
        // 从Resource加载
        if (source instanceof Resource) {
            load((Resource) source);
            return;
        }
        // 从Package加载
        if (source instanceof Package) {
            load((Package) source);
            return;
        }
        // 从 CharSequence 加载
        if (source instanceof CharSequence) {
            load((CharSequence) source);
            return;
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }

    private void load(Class<?> source) {
        if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            // Any GroovyLoaders added in beans{} DSL can contribute beans here
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
            ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
        }
        if (isEligible(source)) {
            // 将启动类的 BeanDefinition注册进 beanDefinitionMap
            this.annotatedReader.register(source);
        }
    }
}

2.2.2 load()

当前我们的主类会按Class加载

public class AnnotatedBeanDefinitionReader {

    public void register(Class<?>... componentClasses) {
        for (Class<?> componentClass : componentClasses) {
            registerBean(componentClass);
        }
    }

    public void registerBean(Class<?> beanClass) {
        doRegisterBean(beanClass, null, null, null, null);
    }

    private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
                                    @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
                                    @Nullable BeanDefinitionCustomizer[] customizers) {
        // 将指定的类封装为AnnotatedGenericBeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }

        abd.setInstanceSupplier(supplier);
        // 获取该类的 scope 属性
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                } else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                } else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        if (customizers != null) {
            for (BeanDefinitionCustomizer customizer : customizers) {
                customizer.customize(abd);
            }
        }

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 将该BeanDefinition注册到IoC容器的beanDefinitionMap中
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
}

public abstract class BeanDefinitionReaderUtils {

    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
}

registerBeanDefinition()

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                // 最后一次校验了
                // 对bean的Overrides进行校验,还不知道会在哪处理这些overrides
                ((AbstractBeanDefinition) beanDefinition).validate();
            } catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
        // 判断是否存在重复名字的bean,之后看允不允许override
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                // 如果该类存在,且不允许 Overriding 直接抛出异常
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            } else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 如果该类存在,且允许 Overriding,直接注册进beanDefinitionMap中
            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            } else {
                // Still in startup registration phase
                // 如果仍处于启动注册阶段,注册进beanDefinitionMap
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        } else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }
}
从0开始图形学(光栅化) 从0开始图形学 阅读详情

相关推荐

深入解析车载以太网DoIP诊断:Wireshark实战TCP/UDS报文分析

本文深入解析车载以太网DoIP诊断,重点介绍如何利用Wireshark进行TCP/UDS报文实战分析。文章详细讲解了从以太网帧、IP帧、TCP段到DoIP协议及UDS服务的逐层拆解方法,并提供了使用Wireshark定位通信故障(如乱序、丢包、重传)的实用技巧,帮助工程师高效排查车载诊断网络问题。

c2d3e4f的博客 674

SpringBoot源码解析(十四)prepareContext

本文继续SpringApplication的run方法往下分析,看prepareContext这行代码 先看下几个入参,context是刚新建的容器,environment是已经完成了配置文件装在等一系列加工的环境对象,listeners中有一个事件发布器,内部含有springboot内置的监听器列表,applicationArguements是对命令行参数的一个封装,printerBanner是上面打印过的启动banner 进入方法实现 private void prepareContext(C

m0_37298252的博客 1968

基于three.js的室内全景3D展馆案例分享

3D场景展厅

acheng 3558

SpringBoot源码分析(7)--prepareContext/准备应用上下文

二、prepareContext 2.1、context.setEnvironment 2.2、postProcessApplicationContext(context); 2.3、applyInitializers(context) 2.4、发布ApplicationContextInitializedEvent事件 2.5、打印启动和profile日志 2.6、注册单例Bean 2.6.1、手工注册单例Bean流程 2.7、初始化BeanDefinitionLoader, 加载Application

weixin_49114503的博客 943

SpringBoot+Vue前后端分离项目实战:个人博客系统

MyBlog主要是基于 SpringBoot + Vue 前后端分离开发的一款动态个人博客系统,后台和前台均通过JSON数据做交互,主要功能有文章管理、分类管理、标签管理、附件管理、评论管理、友链管理、个人资料/博客信息管理等。

Myles'Blog 1万+

20 Embedding 与向量检索:语义为什么能变成距离

Embedding 是 RAG 语义检索的数学基础。本文用工程视角讲清文本如何变成向量,为什么语义相近会表现为距离相近,Top-K 检索如何工作,以及在模型选择、同模型约束、精确匹配和召回评估上的常见坑。

老于的笔记的专栏 6202

SpringBoot源码学习 prepareContext()方法

刷新应用上下文前的准备阶段。也就是prepareContext()方法。 首先看prepareContext()方法。 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,

weixin_47277897的博客 951

openharmony之启动恢复子系统详解

需求: 添加一个名为my_service的自定义服务步骤1: 创建服务配置],],"env": [步骤2: 添加到主配置],"jobs": ["cmds": [步骤3: 验证配置# ✅ 检查配置格式 jq . /system/etc/init/my_service.cfg # 🔄 重新加载配置 begetctl reload # 📊 验证服务状态 begetctl dump_service my_serviceOpenHarmony init进程的完整生命周期。🔄 三阶段启动模型⚙️ 配置体系。

m0_67505153的博客 597

【spring-boot】SpringApplication学习——prepareContext()方法详解

写在前面 在SpringApplication的run()方法启动spring应用的过程中,有三个非常重要的方法,与IOC容器的初始化有关,分别是: createApplicationContext() prepareContext(); refreshContext(); 这里主要记录关于prepareContext()方法有关的学习笔记。 主要的参数列表 参数类型 参数简要说明 ...

Shannon076的博客 985

使用R语言中的NbClust包确定最佳聚类簇数

聚类分析是一种常用的数据分析技术,它将相似的数据点分组成不同的簇。NbClust包是R语言中一个强大的工具,它提供了多种方法来帮助我们确定最佳的聚类簇数。综上所述,使用R语言中的NbClust包可以帮助我们确定最佳的聚类簇数。通过选择适当的聚类算法和评估指标,我们可以更好地理解数据集的结构和模式,并根据需要进行进一步的分析和解释。此外,NbClust包还提供了其他函数和参数,用于执行不同的聚类算法、选择不同的评估指标等。安装完毕后,我们需要加载NbClust包,以便使用其中的函数。函数来确定最佳聚类簇数。

2301_79326559的博客 2278

GEE必须会教程——一文教会你研究区域分块计算与合并

一整块算不是挺好的吗?emmmm,用过的人都知道,GEE好比幼年期的“紫妍”,要用“丹药”来养的,除非你是萧炎小友,到哪都有人给爆金币。我们今天想做的是计算2020年夏季西藏自治区的植被覆盖度(FVC),FVC的估算需要使用归一化植被指数(NDVI数据),这里我们用到的产品是MODIS的相关数据产品,该产品的分辨率是25 0m。下载好的结果毕竟是一块一块的,怎么对下载好的结果进行拼接,变成一张大图呢,别急,接下来,我们上科研小霸王——R语言。此处,我们通过省份数据,按照属性筛选,得到西藏自治区的行政边界。

Promising_GEO的博客 2510

Spring Boot 项目启动时在 prepareContext 阶段做了哪些事?

如果你对Spring Boot 启动流程还不甚了解,可阅读《Spring Boot 启动流程详解》这篇文章。如果你已了解,那就让我们直接看看prepareContext() 源码。接下来让我们详细的看看每个步骤具体做了什么。

若千年后 3082

safetymonitorapi

Summary of SA8653 Safety Monitor API Introduction This document details Safety Monitor APIs for the SA8653 QNNX platform, covering dual interfaces of APSS and SAIL. It defines core data structures and enumerations for subsystems, fault severity and health

qq_39257814的博客 1588

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Springboot启动流程:SpringApplication.run()方法核心逻辑

在上一篇文章【构造SpringApplication实例对象】中我们分析了SpringApplication的构造方法,但是SpringApplication.run()需要返回ConfigurableApplicationContext对象实例,所以下面来一起看下run()中的逻辑。 run方法的代码有点长我们将抛弃掉一些比较次要的内容: public ConfigurableApplicationContext run(String... args) { // 声明一个Context容器

蒋蒋 1122

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

SpringBoot启动流程

SpringBoot启动后完成的工作

parkerJ 415

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SpringBoot启动流程详解

SpringBoot启动流程主要分为两个步骤 一、创建SpringApplication对象。 二、调用SpringApplication对象的run()方法实现启动,并且返回当前容器的上下文。 流程详解: 一、创建SpringApplication对象,SpringBoot容器的初始化操作。 二、获取当前应用的启动类型。 原理:判断当前classpath是否有加载servlet类。 WebAp...

西米_哥哥 874

springboot run方法执行流程详解(三)——prepareContext

9 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); 老样子,点进去看看: context.setEnvironment(environment);这一步不用多少,就是将环境变量set到context中,设置上下文的环境。 this.postProcessApplicationContext(context);这步操作主要是对ApplicationContext进行后置处

三3三的博客 578

Spring源码:SpringBoot启动流程分析

通过百度网盘分享的文件:链接:https://pan.baidu.com/s/1fnt5fWSBLY7UfFPoZFyZpQ?pwd=gyg1 提取码: 按着按键点击方法:继续按着按键点击方法:继续按着按键点击构造方法:继续按着按键点击构造方法:我们逐步来分析SpringApplication构造方法中具体在什么事情::resourceLoader是null,所以赋值也是null:将主启动类放到集合中,后续会使用到,知道有这么回事就行,看到时再提一下:获取当前的web环境,即使用还是,我们使用环境 :往中放

qq_42449963的博客 1079

SpringBoot加载配置与启动流程

SpringBoot加载配置和启动流程

Lyndon的专栏 723

三分钟了解 SpringBoot 的启动流程

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 10:33更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2021超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库中间件 Sharding-JDBC 和 MyCAT 源码解析作业调度中间件 E...

芋艿V 194

SpringBoot的自动装配源码分析

在传统的Spring框架中,我们需要手动配置和管理Bean的依赖关系,但在Spring Boot中,大量的配置可以自动完成。这是因为Spring Boot中引入了自动装配的概念。自动装配指的是根据应用程序的依赖关系自动配置Spring Bean,而无需手动配置。手动装配比如在下面代码中,我创建了一个cat和一个dog。然后通过手动方式把他注入到people类的属性cat和dog中。自动装配。

qq_48157004的博客 733

简单聊聊 SpringBoot 框架执行源码

一条主线构造收集 SPI → 准备环境(加载配置) → 创建空容器 → 填充上下文 → refresh(解析配置类 + 条件装配 + 启动 Tomcat + 实例化单例) → 发布就绪事件 → 执行 Runner。三个扩展点(refresh 前改容器)、(监听启动全生命周期事件)、(就绪后执行一次性逻辑)。面试时先画事件时间线 + refresh 12 步,再把"自动装配在哪步、Tomcat 在哪步"钉到具体步骤上,基本就聊透了。

weixin_47626220的博客 489

SpringBoot 启动过程和自动装配

SpringBoot 启动过程和自动装配

qlxin2080的博客 656

SpringBoot2.1.X 启动原理

Spring Boot 大大简化了我们的开发配置,节省了大量的时间,确实比较方便。但是对于新手来说,如果不了解其中原理,难免会遇到一些坑。 所有的SringBoot 项目都会看到以下这个类: 1、启动类注解 我们从注解看起,进入 @SpringBootApplication 源码可以看到,除了最基础的注解外,还增加了三个 @SpringBootConfiguration、@E...

分享我的点点滴滴,在成长路上与你同行! 356

SpringBoot 启动过程——第一层

进入Debug单步运行SpringBoot 来探究应用启动的时候进行了什么步骤。 我们首先在入口的地方打上断点。自定义一个bean,用来测试spring如何创建对象,也打上断点。

yao09605的博客 352
上一篇: SpringBoot启动流程分析4--run方法之createApplicationContext()方法
下一篇: SpringBoot启动流程分析6--run方法之refreshContext()方法
fanderboy
博客等级 码龄4年 356粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanderboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值