# springboot启动原理分析

# 创建SpringApplication

  1. 进入SpringApplication时,会初始化参数

  2. 执行构造方法SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

  3. this.webApplicationType = WebApplicationType.deduceFromClasspath()就是判断当前web应用的类型,是响应式的还是servlet

  4. this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories()

    在该项目的所有依赖中的spring.factories文件中,寻找Bootstrapper,也就像这个一样

    根据EnableAutoConfiguration进行查找

    getSpringFactoriesInstances(type, new Class<?>[] {})

  5. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))同样也是在factories中,查找ApplicationContextInitializer.class

  6. 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

  1. 记录应用启动的开始时间

    stopWatch.start()

  2. 创建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() 来完成对引导启动器上下文环境设置

  3. 让当前应用进入headless模式

    configureHeadlessProperty()----> java.awt.headless...

  4. 获取当前程序的运行监听器

    SpringApplicationRunListeners listeners = getRunListeners(args),是从spring.factories中调用getSpringFactoriesInstances()拿取的 SpringApplicationRunListener

​ 在此文件中,也是存在一个

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
1
2
3
  1. 遍历 SpringApplicationRunListener 调用 starting 方法;

    相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting

    listeners.starting(bootstrapContext, this.mainApplicationClass)

  2. 保存命令行参数

    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)

  3. 准备环境 prepareEnvironment();

    返回或者创建基础环境信息对象。StandardServletEnvironment

    配置环境信息对象。

    • 读取所有的配置源的配置属性值。

    绑定环境信息 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成

  4. 创建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
  5. 准备当前容器的基本信息

    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
  6. **刷新IOC容器。**refreshContext()

    创建容器中的所有组件(Spring注解

  7. 容器刷新完成后工作?afterRefresh

  8. 所有监听 器 调用 listeners.started(context); 通知所有的监听器 started

  9. *调用所有runners;**callRunners()

  • 获取容器中的 ApplicationRunner

  • 获取容器中的 CommandLineRunner

  • 合并所有runner并且按照@Order进行排序

  • 遍历所有的runner。调用 run 方法

  1. 如果以上有异常,**
  • 调用Listener 的 failed
  1. 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
  2. **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....");
    }
}

1
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
1
2
3
4
5
6
7
8

从启动打印就可以看出,他们执行的时机