SpringBoot启动流程[1] - 配置引导流程

775 阅读3分钟

run[1] - 配置引导流程

在上一部分中,我们已经分析了SpringApplication的构造方法。现在,我们来看看最重要的run方法。

在看源码之前,我们先想一想对于这个方法,我们调用的现象,和我们的预期是什么:

  • 调用了这个方法之后,我们的应用就启动起来了
  • 那么,这个方法,想来应该就是启动Spring应用的关键流程了。根据上面构造方法的分析,这里应该和listener和initializer是有相关联的。

那么接下来就来看看这些代码,这一次我们只看这一些:

 public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    //....
      
 }

开启了一个StopWatch,来监控启动时使用的时间。

随后开始构建一个DefaultBootstrapContext

1.构建引导context

这里就遇到了Spring中第二个重要的概念:

  • context

context顾名思义就是上下文。

根据我们开发的经验,上下文context这个变量的含义,基本上就包括了:

  • 开发过程中,我们需要的所有信息。

而bootStrap的意思是引导,在编程里一般都在初始化的过程里出现。

根据这一信息,我们也很好理解这一行代码为什么会出现在这里:

  DefaultBootstrapContext bootstrapContext = createBootstrapContext();

这个方法如下:

 private DefaultBootstrapContext createBootstrapContext() {
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
    return bootstrapContext;
 }

正如我们预测的一样

bootstrapRegistryInitializers

在后面排上用处了。

不过默认应用bootstrapRegistryInitializers,因此这里基本上啥都没做,这里也就不做深究。

回到主流程

在初始化引导上下文之后,声明了一个context变量,看起来这个应该就是我们在流程中使用的上下文对象了,不过这里是个null,我们就先按下不表,等用到的时候我们再看看具体的结构。

接下来流程中配置了一些系统变量:

2.configureHeadlessProperty

 private void configureHeadlessProperty() {
    System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
          System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
 }

这个东西和我们Spring服务没啥关系,不过说个题外话,这里的东西其实配置的是:

  • java应用在缺失显示器等输入输出设备时,可以正常启动

blog.csdn.net/michaelgo/a…

这篇文章里说的很清楚了,网上的资料也很多,这里就不做过多赘述。

3.runListeners

接下来就拿出了我们当时设置的那些listener,并发布启动消息:

 SpringApplicationRunListeners listeners = getRunListeners(args);
 listeners.starting(bootstrapContext, this.mainApplicationClass);
 ​
     private SpringApplicationRunListeners getRunListeners(String[] args) {
         Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
         return new SpringApplicationRunListeners(logger,
                 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
                 this.applicationStartup);
     }

这里就看到了之前详细了解过的

getSpringFactoriesInstances

这里我们获取了runListener,通过我们的boosstrapContext,发布了启动消息。

这里的listener,都是一些基础级别的设施,比如:日志,文件编码等等,按下不表。

总结

至此我们分析了到run方法到try前进行的步骤,在解析中我们可以很清楚的看清楚:

  • 这些步骤实际上并没有涉及到Spring的核心bean,只是做一些正式初始化前的准备工作,包括:

    • 构建引导上下文
    • 设置无输入输出设备时依然可以启动
    • 通过监听者模式,发布了当前类start事件。

到此的知识合计

  • 设计模式:

    • 这里以及上一篇的构造方法,Spring中应用了如下这些设计模式:

      • 监听器模式

        • 这里明确地使用了监听者模式:

           listeners.starting(bootstrapContext, this.mainApplicationClass);
          
        • 工厂模式:

           getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
          

          这里通过类名和反射,构建了工厂实例。

    • 核心知识涉及

      • 到这里为止,出现过我们熟知的Spring核心类bean实际上比较少:

        • context

          • DefaultBootstrapContext : 默认启动引导上下文
          • ConfigurableApplicationContext : 这里只做了声明,实际上还是空的

        \