目录

Spring Boot启动流程

SpringApplication启动流程

以spring boot 2.2.5.RELEASE版本为例, 详细解析启动过程:

启动类, 即主配置类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

// 1.创建一个SpringApplication对象
// 2.调用了SpringApplication对象的run()
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
}

创建SpringApplication对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // 1.保存主配置类, 它是主要的bean来源, 也就是@SpringBootApplication注解的类
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 2.推断web应用类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 3.从classpath下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;实例化并配置好它们
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 4.从classpath下找到ETA-INF/spring.factories配置的所有ApplicationListener;实例化并配置好它们
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 5.从堆栈信息中推断有main方法的主配置类, 也就是@SpringBootApplication注解的类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

调用SpringApplication对象的run()方法

 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
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    // 1.从类路径下META-INF/spring.factories获取SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 2.回调所有的获取SpringApplicationRunListener.starting()方法
    listeners.starting();
    try {
        // 3.封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 4.准备环境,调用prepareEnvironment方法
        //方法中创建环境完成会后回调SpringApplicationRunListener#environmentPrepared();表示环境准备完成
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 5.打印Banner图(就是启动时的标识图)。
        Banner printedBanner = printBanner(environment);
        // 6.创建ApplicationContext,决定创建web的ioc还是普通的ioc  
        context = createApplicationContext();
        // 7.异常分析报告
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 8.准备上下文环境,将environment保存到ioc中
        // applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法 
        // listeners.contextPrepared(context):回调所有的SpringApplicationRunListener的contextPrepared(),
        // listeners.contextLoaded(context): prepareContext()最后会回调所有的SpringApplicationRunListener的contextLoaded()
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 9.刷新容器,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
        // 扫描,创建,加载所有组件的地方,(配置类,组件,自动配置)
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        // 10.所有的SpringApplicationRunListener回调started方法
        listeners.started(context);
        // 11.从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调,
        // ApplicationRunner先回调,CommandLineRunner再回调
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        // 12.所有的SpringApplicationRunListener回调running方法
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    // 13.整个SpringBoot应用启动完成以后返回启动的ioc容器
    return context;
}

流程图

/images/202003/springboot13.svg

自动配置原理

@EnableAutoConfiguration自动配置的魔法骑士就变成了:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

然后各种自动配置类依次执行,利用@condition注解,根据容器中的bean,classpath下的class, 配置文件中的属性,来综合决定给功能要不要配置, 如何配置.

我们知道, 自动配置的目的是配置好相应的bean放到容器中, 供我们使用.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

Reference