详细分析需看源码
SpringBoot启动流程
SpringBoot启动分为两大步七小步
一,启动准备
- 首先SpringBoot会判断当前是web应用还是,响应式应用(Reactive),还是普通应用
- 利用SPI机制(ETA-INF/spring.factories),找到所有的初始化器和监听器并待命
二,执行启动
- 准备环境:根据你的application.xml配置文件,环境变量,命令行参数等准备环境,组成环境对象
- 创建容器:根据第一步确定的类型,创建一个空的SpringIOC容器
- 容器刷新:Spring会解析@SpringBootApplication,通过扫描所有Bean,进行自动配置(Web应用内嵌的TomCat在此时启动)
- 收尾工作:容器刷新后,发布完成事件,通知所有监视器
- 执行回调:检测有无实现CommandLineRunner或ApplicationRunner的Bean,并执行它们的run方法
SPI详解
SPI机制是一种"发现",是运行时多态和反射的体现
有这么一台电脑
SPI前:1接口必须插鼠标USB,2必须键盘
SPI后:1接口被插入USB,检测为键盘,处理键盘输入
代码示例
- 定义接口
java
package com.example;
public interface Animal {
void speak();
}
- 写入实现类
java
// 狗
package com.dog;
public class Dog implements Animal {
public void speak() {
System.out.println("汪汪汪");
}
}
// 猫
package com.cat;
public class Cat implements Animal {
public void speak() {
System.out.println("喵喵喵");
}
}
- 创建SPI配置文件resources/META-INF/services/
- 文件名必须是:接口的全限定名(包含包名)
- 这里就是:com.example.Animal
- 文件内容:com.dog.Dog
com.cat.Cat
- 运行发现
java
public class Main {
public static void main(String[] args) {
// ServiceLoader是Java自带的SPI加载器
ServiceLoader<Animal> loader = ServiceLoader.load(Animal.class);
// 遍历所有找到的动物
for (Animal animal : loader) {
animal.speak();
}
}
}
// 输出:
// 汪汪汪
// 喵喵喵
初始化器
初始化器执行时机:容器刷新前,创建容器后
干了啥:
- 添加自定义环境变量
- 激活某个 profile(dev/test/prod)
- 提前注册一些特殊的 Bean
监听器
| 事件 | 触发时机 | 可以干啥 |
|---|---|---|
| ApplicationStartingEvent | 刚点启动,啥都没做 | 初始化日志系统 |
| ApplicationEnvironmentPreparedEvent | 配置文件加载完了 | 修改环境变量、激活profile |
| ApplicationContextInitializedEvent | 容器刚创建 | 容器还没开始干活 |
| ApplicationPreparedEvent | Bean定义加载完了 | 可以查看有哪些Bean |
| ApplicationStartedEvent | 容器刷新完成 | Runner还没执行 |
| ApplicationReadyEvent | 全部搞定 | 发送通知、打印banner |
| ApplicationFailedEvent | 启动失败 | 发告警邮件、记录错误 |