SpringBoot从入门到精通—SpringBoot启动流程剖析


       上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。

1、基于源码简单剖析SpringBoot的启动流程

Spring boot的启动过程:

SpringBoot应用启动后首先执行SpringBoot启动类的main方法中的public static ConfigurableApplicationContext run(Class<?> primarySource, String... args)这个run方法,他又调用了重载方法的public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args),在这个run方法中调用了真正的run方法。

他们的调用关系如下图:

在调用正真干活的run方法之前,SpringAppication先进行了初始化:

最终真正干活的run方法

该方法中有几个关键的步骤

(1)创建了应用监听器SpringApplicationRunListeners并开始监听
(2)加载SpringBoot配置环境ConfigurableEnvironment,如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下:

(3)将从配置文件中加载进来的配置环境(Enviroment)加入到监听器中
(4)创建应用配置上下文对象ConfigurableApplicationContext,我们可以到其具体的实现中看看:

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

(5)回到run方法继续往下走,prepareContext()方法将listeners、environment、applicationArguments、banner等组件与上下文对象关联
(6)调用refreshContext()方法是SpringBoot启动中最重要的一步,包括spring.factories的加载,bean的实例化等核心工作。这一步完成后SpringBoot的启动工作基本就完成了。下面是最终真正干活的refresh()方法的截图:

方法首先获取显式获取并设置了应用上下文(applicationContextClass),如果不存在,再根据不同的Web环境选择实例化不同的上下文对象,默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回。

配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成。

启动过程中的一些细节代码说明:

(1)在run方法一开始执行他就new了一个StopWatch,这个类有啥用呢?

开启单步调试,最终发现这个类的功能就是统计一下SpringBoot启动所用的时间并在最会在启动完成打印出来。

(2)在启动中有一个Banner,他的用处就是打印一下SpringBoot的logo

留言区

还能输入500个字符