Spring Boot技术内幕:架构设计与实现原理
上QQ阅读APP看书,第一时间看更新

4.1 run方法核心流程

在分析和学习整个run方法的源代码及操作之前,我们先通过图4-1所示的流程图来看一下SpringApplication调用的run方法处理的核心操作都包含哪些。然后,后面的章节我们再逐步细化分析每个过程中的源代码实现。

图4-1 run方法核心运行流程图

上面的流程图可以看出,SpringApplication在run方法中重点做了以下操作。

·获取监听器和参数配置。

·打印Banner信息。

·创建并初始化容器。

·监听器发送通知。

当然,除了核心操作,run方法运行过程中还涉及启动时长统计、异常报告、启动日志、异常处理等辅助操作。

对照流程图,我们再来整体看一下入口run方法的源代码,核心部分的功能已通过注释的形式进行说明。


public ConfigurableApplicationContext run(String... args) {
    // 创建StopWatch对象,用于统计run方法启动时长
    StopWatch stopWatch = new StopWatch();
    // 启动统计
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 配置headless 属性
    configureHeadlessProperty();
    // 获得SpringApplicationRunListener 数组
    // 该数组封装于SpringApplicationRunListeners对象的listeners中
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 启动监听,遍历SpringApplicationRunListener数组每个元素,并执行
    listeners.starting();
    try {
        // 创建ApplicationArguments对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
        // 加载属性配置,包括所有的配置属性(如:application.properties中和外部的属性配置)
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 打印Banner
        Banner printedBanner = printBanner(environment);
        // 创建容器
        context = createApplicationContext();
        // 异常报告器
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 准备容器,组件对象之间进行关联
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 初始化容器
        refreshContext(context);
        // 初始化操作之后执行,默认实现为空
        afterRefresh(context, applicationArguments);
        // 停止时长统计
        stopWatch.stop();
        // 打印启动日志
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        // 通知监听器:容器启动完成
        listeners.started(context);
        // 调用ApplicationRunner和CommandLineRunner的运行方法。
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        // 异常处理
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 通知监听器:容器正在运行
        listeners.running(context);
    } catch (Throwable ex) {
        // 异常处理
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

在整体了解了整个run方法运行流程及核心代码后,下面我们针对具体的过程进行讲解。