浅谈springboot启动过程

1. 知识回顾

为了后文方便,我们先来回顾一下spring的一些核心概念。

spring最核心的功能无非是ioc容器,这个容器里管理着各种bean。ioc容器反映在java类上就是spring的核心类ApplicationContext。ApplicationContext有众多的子接口和子类,不同的实现类有不同的功能。比如ClassPathXmlApplicationContext支持从xml读取bean定义并注册到容器中,AnnotationConfigApplicationContext支持读取@Configuration、@Service等注解定义的bean。

ClassPathXmlApplicationContext和AnnotationConfigApplicationContext代表了我们定义bean的两种最常见方式,即xml和注解方式。还有一种方式是通过@Import来导入bean的定义。如下代码示例了@Import的一种用法。

@Configuration
public class AppConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

@Import(AppConfig.class)
public class AppMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppMain.class);
        MyBean bean = context.getBean(MyBean.class);
        System.out.println(bean);
}

@Import还有一种用法就是@Import(XxxImportSelector.class),其中XxxImportSelector是ImportSelector这个接口的实现类。下面演示了@Import(XxxImportSelector.class)的用法。

// 一个普通的java类
public class TestImportSelector {
}

// ImportSelector的实现类。
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.example.springbootsimple.service.TestImportSelector"};
    }
}

// 测试ImportSelector
@Import(MyImportSelector.class)
public class AppMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppMain.class);
        TestImportSelector bean = context.getBean(TestImportSelector.class);
        System.out.println(bean);
    }
}

如上代码运行后,spring容器中就会有TestImportSelector这个bean了,原理是如果@Import()中要import的是一个ImportSelector的实现类,spring就会自动调用ImportSelector.selectImports方法,这个方法会返回一个包含类名的String数组,spring会根据这些类名实例化类,注册到spring容器中。

2. 最简单的springboot启动

我们用springboot启动web应用用得比较多,用多了以后,往往会觉得springboot只能这么用,其实不然,我们先抛开各种配置,从最简单的springboot启动开始看,如下代码是最简单的springboot启动,注意AppMain类上没有任何注解。

public class AppMain {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(AppMain.class);
        // 打印 org.springframework.context.annotation.AnnotationConfigApplicationContext        
        System.out.println(context.getClass().getName());
    }
}

上面代码可以成功运行(注意成功运行的前提是只引入org.springframework.boot:spring-boot,不要引入spring-boot-starter-web)。我把SpringApplication.run的返回值也打印出来了,是想告诉你,springboot的启动过程其实就是创建一个ApplicationContext的过程。所以,别人问你springboot启动过程是什么时,你就可以说,就是创建了一个ApplicationContext,完事。如果我们从宏观角度来看,这个问题就是这么简单。当然,这个答案肯定不会让人满意,但是不要着急,我们要从简单到复杂,从宏观到微观,这样才能看清事物的本质。

3. 带Web应用的springboot启动

3.1 启动示例

我们引入spring-boot-starter-web,然后执行如下代码。

@SpringBootApplication
public class AppMain {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(AppMain.class);
        System.out.println(context.getClass().getName());
    }
}

此时,打印出的结果是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext,可以看到和我们第一个例子打印的ApplicationContext不一样了。springboot是如何确定用哪个ApplicationContext的?AnnotationConfigServletWebServerApplicationContext做了什么事情,让我们什么也没做就启动了一个tomcat的web容器?

3.2 如何确定用哪个ApplicationContext?

我们追溯SpringApplication.run方法的源码,会看到如下run方法,这个方法就是比较核心的启动流程了。

我们不需要每一行代码都关心,因为那样会让我们迷失在源码里,我们通过方法名,我们很容易看出来 context = createApplicationContext();这一行代码就是在创建一个ApplicationContext,所以我们看下这个方法源码。

 createApplicationContext();会调用DefaultApplicationContextFactory.create(WebApplicationType webApplicationType)这个工厂类来创建ApplicationContext。从上面代码可以看出,DefaultApplicationContextFactory相当于是一个代理,它会通过SpringFactoriesLoader.loadFactories加载其他ApplicationContextFactory来创建Application,如果其他工厂类没的返回结果,就会用默认的AnnotationConfigApplicationContext。SpringFactoriesLoader.loadFactories这个方法有兴趣的可以研究下,这个方法会到spring.factories这个文件里加载你想要的类,spring-boot jar包的spring.factories里定义了如下两个ApplicationContextFactory类,所以这两个类会被加载进来用于创建ApplicationContext。

上面两个Factory从名字也能很容易辨别,一个是用来创建ServletWeb应用的,一个是用来创建ReactiveWeb应用的。如下图是AnnotationConfigServletWebServerApplicationContext.Factory的create方法,可以看到如果webApplicationType是SERVLET类型,就会创建AnnotationConfigServletWebServerApplicationContext。

从上述源码来看,我们第一个疑问已经解决了,springboot会根据wepApplicationType的类型来决定创建什么样的ApplicationContext。至于WebApplicationType如何确定,看下WebApplicationType#deduceFromClasspath就可以了,比较简单,比如会根据类路径下是否有javax.servlet.Servlet等来判断web类型是否是SERVLET等等。当我们引入spring-boot-starter-web时,这个引用就会包含对servlet的引用,所以我们创建的就是SERVLET类型的WebApplicationType。

 3.3 AnnotationConfigServletWebServerApplicationContext做了什么?

现在ApplicationContext创建好了,我们也知道什么情况下会创建什么类型的ApplicationContext了,但是这个ApplicationContext还是个比较原始的,很多事情都还没做。了解过一些spring源码的应该知道,ConfigurableApplicationContext有个非常重要的方法:refresh方法。这个方法内部会解析bean的定义,创建好单例bean,应用bean后处理器等。AnnotationConfigServletWebServerApplicationContext就是在refresh方法中搞了点事情,启动了tomcat容器。org.springframework.context.support.AbstractApplicationContext#refresh方法内会调用onRefresh()方法,AnnotationConfigServletWebServerApplicationContext就是重写了onRefresh方法,在这个方法里启动了tomcat。

至于tomcat是如何创建并启动的,这又是另一个话题了,感兴趣的可以自行研究。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18723.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文旅数字人出圈不断,文旅数字人宣传片制作赋能数字文旅新业态

在文旅产业发展中 数字人的应用越来越广泛 文旅借助数字人浪潮 把传统文化与科技相融合 以Z世代年轻群体所喜爱的方式 推动文旅数字化发展 文旅数字人应用场景——数字人文旅宣传片 可以让数字人作为文旅宣传片主角,串联当地代表性的历史文化地标、现代都市场景…

sensor的感光原理

文章内容来自网络,联系我可以删掉。 目录 CMOS sensor上有什么? 不同像素对应的图像质量: 像点感光原理: Bayer格式变换成RGB格式: CMOS sensor上有什么? CMOS sensor 通常由像敏单元阵列、行驱动器、…

第10章:数据处理增删改

一、插入数据 CREATE TABLE emp1 (id int(11) ,name varchar(15) ,hire_date date ,salary double(10,2) )1.添加一条数据 ①没有指明添加的字段,一定按照顺序添加 insert into emp1 values(1,wang,2000-4-4,5900)②指明添加的字段(推荐)…

【CSS3】CSS3 属性选择器 ( CSS3 简介 | 属性选择器 | 属性选择器权重 )

文章目录 一、CSS3 简介二、CSS3 属性选择器权重三、CSS3 属性选择器 一、CSS3 简介 CSS3 是在 CSS2 基础上进行扩展后的样式 ; 在 移动端 对 CSS3 的支持 要比 PC 端支持的更好 , 建议在移动端开发时 , 多使用 CSS3 ; PC 端老版本浏览器不支持 CSS3 , 尤其是 IE 9 及以下的版…

Qt5.9学习笔记-事件(五) 事件调试和排查

⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三…

【超详细】【YOLOV8使用说明】一套框架解决CV的5大任务:目标检测、分割、姿势估计、跟踪和分类任务【含源码】

目录 1.简介2.环境安装2.1安装torch相关库2.2 获取yolov8最新版本,并安装依赖 3. 如何使用模型用于各种CV任务3.1 目标检测任务实现检测图片代码检测视频代码 3.2 分割任务实现分割图片代码分割视频代码 3.3 追踪任务3.4 姿态检测任务姿态检测(图片&…

数据结构之“树”——二叉树、红黑树、B树、B+树、B*树

这篇文章主要简单总结下二叉树、红黑树、B树、B树、B*树的基本结构和原理。 一、二叉树 二叉树就是度不超过2的树(每个结点最多有两个子结点)。 二叉树是有序树(二叉排序树),若将其左右子树颠倒,则成为另一棵不同的二叉树。 二叉…

php+vue+mysql医院医护人员医生排班系统

本医护人员排班系统管理员,医护。管理员功能有个人中心,医院信息管理,医护信息管理,医护类型管理,排班信息管理,排班类型管理,科室信息管理,投诉信息管理。医护人员可以修改自己的个…

「二线豪华」或成历史,理想反超沃尔沃再树「里程碑」

今年的上海车展,除了占据C位的新能源汽车,还有传统车企。 上海车展开幕前,沃尔沃汽车大中华区销售公司总裁钦培吉在新车发布会上直言:“新势力会的,我们三年就学会了;我们会的,新势力十年都学不…

Android安装apk出现 “安装包无效”或“安装包不兼容”的解决方案

Android 安装apk出现“安装包无效”或“安装包不兼容”解决方案 1. 问题出现2. 配置 build.gradle3. 生成Signed APK 1. 问题出现 使用Android Studio安装apk到手机一切正常,但是分享出去出现安装apk出现“安装包无效”或“安装包不兼容”问题 这种情况需要我们设…

4 IK分词器

4 IK分词器 4.1测试分词器 在添加文档时会进行分词,索引中存放的就是一个一个的词(term),当你去搜索时就是拿关键字去匹配词,最终 找到词关联的文档。 测试当前索引库使用的分词器: post 发送&#xff…

【分布式理论】聊一下 ACID、BASE、CAP、FLP

分布式理论基础 今天我们来聊一下分布式相关基础理论基础,上一篇文章中,我描述了一下分布式系统的纲,但是想要入手学习分布式系统设计,其实需要先从基本理论开始。而知名的ACID、BASE、CAP、FLP都是相关的理论基础。 ACID ACID…

六、FM1288调试方案-调试过程及细节

本篇文章,主要讲述实际调试操作:具体到需要调节哪些寄存器,调节完后,会有什么样的变化。但是整体效果不能达到我们期望的绝对感觉,所以我先把我们调试的结果放在前面,如果觉得不理想,也可以不看后面的内容了。 文章目录 1. 调试准备1.1 建立与FM1288芯片通信1.2 Uart结…

什么是多相流?在熟悉工业中常见的两相及多相流的分类及特点

文章目录 一、多相流的概览1.相的概念 二、多相流的引入单相流与多相流: 三、多相流及特性介绍四、常见的多相流的分类及特点1、常见的两相及多相流3、两相流动力学的发展简史4、两相流的研究方法和理论模型 一、多相流的概览 1.相的概念 物理学: 自然界中物质的态…

基于simulink使用麦克风阵列的声波束成形

一、前言 此示例演示如何对麦克风阵列接收到的信号进行波束化,以在嘈杂环境中提取所需的语音信号。 二、模型的结构 该模型模拟在 10 元件均匀线性麦克风阵列 (ULA) 上接收来自不同方向的三个音频信号。在接收器处添加热噪声后,应…

智慧厕所引导系统的应用

智慧公厕引导系统是一种基于智能化技术的公厕管理系统,可以为如厕者提供更加便捷、舒适、安全的如厕环境和服务,同时也可以引导如厕者文明如厕,营造文明公厕的氛围。智慧公厕引导系统可以通过智能引导屏、手机小程序等方式,为如厕…

【存储数据恢复】NetApp存储WAFL文件系统数据恢复案例

存储数据恢复环境: NetApp存储设备,WAFL文件系统,底层是由多块硬盘组建的raid磁盘阵列。 存储故障: 工作人员误操作导致NetApp存储内部分重要数据被删除。 存储数据恢复过程: 1、将存储设备的所有磁盘编号后取出&…

Linux上Nacos基本使用:连接MySQL并修改密码、启动、停止命令等

Nacos如何连接MySQL并修改密码 说明如何将内嵌数据库Derby切换为MySQL数据库直接新建MySQL数据库: 必须是MySQL5.7及以上 如何修改密码启动、停止命令 说明 nacos默认: 使用内嵌的数据库(Derby)默认登录地址 ip:8848/nacos; 账号&#xff1…

React 组件

文章目录 React 组件复合组件 React 组件 本节将讨论如何使用组件使得我们的应用更容易来管理。 接下来我们封装一个输出 “Hello World&#xff01;” 的组件&#xff0c;组件名为 HelloMessage&#xff1a; React 实例 <!DOCTYPE html> <html> <head> &…

JVM系列-第7章-对象的实例化内存布局与访问定位

对象的实例化内存布局与访问定位 对象的实例化 大厂面试题 美团&#xff1a; 对象在JVM中是怎么存储的&#xff1f;对象头信息里面有哪些东西&#xff1f; 蚂蚁金服&#xff1a; 二面&#xff1a;java对象头里有什么 对象创建的方式 new&#xff1a;最常见的方式、单例…