抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

SpringBoot启动流程

  • 创建 SpringApplication 对象。
  • 构造函数中初始化 Initializer(setInitializers) 和 Listener(setListeners)。
  • 调用 run 方法。
  • 开启定时器 StopWatch, stopWatch.start(), 监听器, 记录启动时间。
  • 根据 SpringApplicationRunListeners 以及参数来初始化环境。
  • 准备环境配置, 注意 ConfigFileApplicationListener 是用来加载 properies 文件的。
  • 打印 banner. printBanner()方法。
  • 创建容器上下文 createApplicationContext
  • prepareContext 准备容器上下文, 执行之前的 Initializer 初始化, 并 loadbean
  • refreshContext 刷新容器上下文, 里面 onRefresh 方法启动 web server
  • afterRefresh 执行初始化完成后要做的操作,目前是空的。
  • 关闭计时器. stopWatch.stop()
  • listener 启动完成。
  • 打印启动时间。

WebApplicationType web应用类型, NONE, SERVLET, REACTIVE.

Servlet web, 传统的 MVC Web项目。

Reactive web, 响应式Web项目(WebFlux)。

spring.factories 文件中配置有需要初始化的bean对象

引入 springboot 包的过程, 本质就是往 class path 下面放入 spring.factories 这个文件里配置类的过程。这样启动过程中就会自主地把这些类加载进来。

SpringApplication的构造方法。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 初始化 Initialzer,本质是 List 容器
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 初始化 Listener,本质是 List 容器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 获取 main 函数所调用的类
    this.mainApplicationClass = deduceMainApplicationClass();
}

SpringApplicationrun方法。

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    // 开启计时器
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    // 获取 listener 监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 启动中
    listeners.starting();
    try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 准备环境配置 profile。通过 ConfigFileApplicationListener 来加载配置文件
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      // 忽略的 bean
      configureIgnoreBeanInfo(environment);
      // 打印 banner
      Banner printedBanner = printBanner(environment);
      // 创建容器的上下文对象
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
          new Class[] { ConfigurableApplicationContext.class }, context);
      // 准备上下文
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      // 刷新上下文 AbstractApplicationContext -> refresh -> invokeBeanFactoryPostProcessors -> SharedMetadataReaderFactoryContextInitializer register() 
      // 从 env 中获取 spring 所需要的一些数据
      // aware 的组装
      // 这一步加载了bean容器并保存在 beanFactories 中, 也做了 webServer 的启动
      refreshContext(context);
      // 执行Conetext初始化之后要做的操作,目前是空的
      afterRefresh(context, applicationArguments);
      // 关闭计时器
      stopWatch.stop();
      if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // 通知listener启动完成
      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;
}

本质上是对 listener 的不同维护。

ConfigurationClassParser.doProcessConfigurationClass() bean的解析, 可以看到一些注解就在这里进行解析的。

ServletWebServerApplicationContext 的 createWebServer 方法创建 web 容器。

评论