# springboot启动原理分析
# 创建SpringApplication
- 进入 - SpringApplication时,会初始化参数
- 执行构造方法 - SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
- this.webApplicationType = WebApplicationType.deduceFromClasspath()就是判断当前web应用的类型,是响应式的还是servlet 
- this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories() - 在该项目的所有依赖中的 - spring.factories文件中,寻找Bootstrapper,也就像这个一样 - 根据EnableAutoConfiguration进行查找 - getSpringFactoriesInstances(type, new Class<?>[] {}) 
- setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))同样也是在factories中,查找ApplicationContextInitializer.class 
- this.mainApplicationClass = deduceMainApplicationClass()寻找主类方法,也就是含有main方法的类 - private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- "main".equals(stackTraceElement.getMethodName()如果循环到的类,方法名是main,那么就是主类,并且会使用这个主类创建一个对象 
上面的创建SpringApplication的过程,其实就是return new SpringApplication(primarySources).run(args)中的new SpringApplication(primarySources)过程,当创建springApplication完成后,就会调用后面的run()方法运行springapplication
# 运行SpringApplication
- 记录应用启动的开始时间 - stopWatch.start() 
- 创建Bootstrap,这个Bootstrap就是我们从spring.factories中配置的 - DefaultBootstrapContext bootstrapContext = createBootstrapContext() - private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)); return bootstrapContext; }1
 2
 3
 4
 5- 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置 
- 让当前应用进入headless模式 - configureHeadlessProperty()----> java.awt.headless... 
- 获取当前程序的运行监听器 - SpringApplicationRunListeners listeners = getRunListeners(args),是从 - spring.factories中调用getSpringFactoriesInstances()拿取的 SpringApplicationRunListener 
 在此文件中,也是存在一个
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
2
3
- 遍历 SpringApplicationRunListener 调用 starting 方法; - 相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting - listeners.starting(bootstrapContext, this.mainApplicationClass) 
- 保存命令行参数 - ApplicationArguments applicationArguments = new DefaultApplicationArguments(args) 
- 准备环境 prepareEnvironment(); - 返回或者创建基础环境信息对象。StandardServletEnvironment - 配置环境信息对象。 - 读取所有的配置源的配置属性值。
 - 绑定环境信息 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成 
- 创建ioc容器,这是最重要的一步,根据当前的web应用类型,是servlet还是其他的,创建对应容器 - context = createApplicationContext() - ApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch (webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } } catch (Exception ex) { throw new IllegalStateException("Unable create a default ApplicationContext instance, " + "you may need a custom ApplicationContextFactory", ex); } };1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
- 准备当前容器的基本信息 - prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner) - 设置环境 
- ioc容器的后置处理流程 - postProcessApplicationContext(context) 
- 应用初始化器--->applyInitializers(context) - protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }1
 2
 3
 4
 5
 6
 7
 8- 遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能  
- 遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器****contextPrepared 
 
- 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded; - listeners.contextPrepared(context) 
- 得到所有的bean,并且注册 - ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments);1
 2
 
- **刷新IOC容器。**refreshContext() - 创建容器中的所有组件(Spring注解 
- 容器刷新完成后工作?afterRefresh 
- 所有监听 器 调用 listeners.started(context); 通知所有的监听器 started 
- *调用所有runners;**callRunners() 
- 获取容器中的 ApplicationRunner 
- 获取容器中的 CommandLineRunner 
- 合并所有runner并且按照@Order进行排序 
- 遍历所有的runner。调用 run 方法 
- 如果以上有异常,**
- 调用Listener 的 failed
- 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
- **running如果有问题。继续通知 failed 。**调用所有 Listener 的 **failed;**通知所有的监听器 failed
# 自定义事件监听事件组
我们自定义事件监听,只需要考虑程序启动的时候,是去哪里找到这个监听器就行,在程序启动的时候,监听器会从spring.factories和context容器中进行拿取
其中,从spring.factories中拿取的有
org.springframework.context.ApplicationContextInitializer
org.springframework.context.ApplicationListener
org.springframework.boot.SpringApplicationRunListener
这三个
从容器中拿取的有
CommandLineRunner
ApplicationRunner
因为有三个需要从spring.factories中拿取,所以我们就要在META-INF下创建一个spring.factories文件
package cn.vipblogs.test.listener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyApplicationContextInitializer ....initialize.... ");
    }
}
package cn.vipblogs.test.listener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("MyApplicationListener.....onApplicationEvent...");
    }
}
package cn.vipblogs.test.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Order(1)
@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner...run...");
    }
}
package cn.vipblogs.test.listener;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
 * 应用启动做一个一次性事情
 */
@Order(2)
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner....run....");
    }
}
package cn.vipblogs.test.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    private SpringApplication application;
    public MySpringApplicationRunListener(SpringApplication application, String[] args){
        this.application = application;
    }
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("MySpringApplicationRunListener....starting....");
    }
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("MySpringApplicationRunListener....environmentPrepared....");
    }
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener....contextPrepared....");
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener....contextLoaded....");
    }
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener....started....");
    }
    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener....running....");
    }
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("MySpringApplicationRunListener....failed....");
    }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
org.springframework.context.ApplicationContextInitializer=\
  cn.vipblogs.test.listener.MyApplicationContextInitializer
org.springframework.context.ApplicationListener=\
  cn.vipblogs.test.listener.MyApplicationListener
org.springframework.boot.SpringApplicationRunListener=\
  cn.vipblogs.test.listener.MySpringApplicationRunListener
2
3
4
5
6
7
8
从启动打印就可以看出,他们执行的时机

