Spring Boot启动流程

背景

从大学接触Spring 3.0到现在已经有5、6年的时间了,但工作后由于公司有自研的系统,一直没有机会在实际工作中用到。后来听说Spring推出了微服务架构叫做Spring Boot,挺火爆,就尝试着去研究了一段时间。

开始

通过跟踪代码引用,我们可以看到

    public static ConfigurableApplicationContext run(Class[] primarySources,
            String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

从代码可以看出,Spring Boot启动第一步会先构建SpringApplication实例,然后调用其run()方法,并传入命令行参数。

  • 构建SpringApplication
    具体分析参考 构建SpringApplication
  • SpringApplication.run(String... args)
    SpringApplication.run(String... args)方法的具体实现如下,从代码中可以看到,这一过程主要完成了以下工作:
  1. 启动计时器,用来记录程序启动耗时情况
  2. 实例化异常报告器,用于对启动过程进行错误分析
  3. 加载并启动监听器,用于监听ApplicationContext构造过程,并在关键节点完成时,广播对应的事件
  4. 解析命令行参数,并封装到ApplicationArguments实例中
  5. 构建容器运行环境
  6. 打印Banner
  7. 创建ApplicationContext应用上下文
  8. 构建ApplicationContext
  9. 刷新ApplicationContext
    public ConfigurableApplicationContext run(String... args) {
        // 开始计时
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        // 异常报告器
        Collection exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        // 1. 加载并启动监听器,用于监听ApplicationContext构造过程
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            // 解析命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            // 2.构造容器环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            // 设置需要忽略的Bean
            configureIgnoreBeanInfo(environment);
            // 打印Banner
            Banner printedBanner = printBanner(environment);
            // 3.创建容器
            context = createApplicationContext();
            // 4.实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            // 5.准备容器
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            // 6.刷新容器
            refreshContext(context);
            // 7.刷新容器后的扩展接口
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            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;
    }

加载并启动监听器

监听器的作用主要是在Spring Boot启动过程中的关键节点(如:开始启动、环境构建完成、启动成功、启动失败等)抛出一个事件对象,并将该事件对象广播给对应的ApplicationListner监听器,由监听器去完成对应的处理逻辑。
详细信息参考:SpringApplicationRunListener

准备Environment

详细信息参考:Spring Boot启动-构造容器环境

创建ApplicationContext

创建ApplicationContext实现代码如下:

  1. 根据Web应用类型,获取对应的ApplicationContext子类
  2. 实例化ApplicationContext子类
// 常量定义
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."
            + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
            + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
            + "annotation.AnnotationConfigApplicationContext";

    protected ConfigurableApplicationContext createApplicationContext() {
        // 1. 根据Web应用类型,获取对应的ApplicationContext子类
        Class contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        // 2. 实例化子类
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

BeanFactory也是在此过程中被创建

    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

你可能感兴趣的:(Spring Boot启动流程)