new SpringApplication().run(args)之.run(args)分析

175 阅读2分钟
//org.springframework.boot.SpringApplication#run(String... args)
public class SpringApplication {
	//...省略其他方法
  
  public ConfigurableApplicationContext run(String... args) {
      // 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长
     StopWatch stopWatch = new StopWatch();
     stopWatch.start();
     // 初始化应用上下文和异常报告集合
     ConfigurableApplicationContext context = null;
     Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     // 配置 headless 属性
     configureHeadlessProperty();

     //   (1)获取并启动监听器
     SpringApplicationRunListeners listeners = getRunListeners(args);
     listeners.starting();
     try {
        // 创建  ApplicationArguments 对象 初始化默认应用参数类
        // args是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。如:--server.port=9000
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        //(2)项目运行环境Environment的预配置
        // 创建并配置当前SpringBoot应用将要使用的Environment
        // 并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

        configureIgnoreBeanInfo(environment);
        // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
        Banner printedBanner = printBanner(environment);

        // (3)创建Spring容器
        context = createApplicationContext();
        // 获得异常报告器 SpringBootExceptionReporter 数组
        //这一步的逻辑和实例化初始化器和监听器的一样,
        //都是通过调用 getSpringFactoriesInstances 方法来获取配置的异常类名称并实例化所有的异常处理类
        exceptionReporters = getSpringFactoriesInstances(
              SpringBootExceptionReporter.class,
              new Class[] { ConfigurableApplicationContext.class }, context);


        // (4)Spring容器前置处理
        //这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:
        //将启动类注入容器,为后续开启自动化配置奠定基础。
        prepareContext(context, environment, listeners, applicationArguments,
              printedBanner);

        // (5):刷新容器
        refreshContext(context);

        // (6):Spring容器后置处理
        //扩展接口,设计模式中的模板方法,默认为空实现。
        // 如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理
        afterRefresh(context, applicationArguments);
        // 停止 StopWatch 统计时长
        stopWatch.stop();
        // 打印 Spring Boot 启动的时长日志。
        if (this.logStartupInfo) {
           new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        // (7)发出结束执行的事件通知
        listeners.started(context);

        // (8):执行Runners
        //用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序
        //Runner 运行器用于在服务启动时进行一些业务初始化操作,这些操作只在服务启动后执行一次。
        //Spring Boot提供了ApplicationRunner和CommandLineRunner两种服务接口
        callRunners(context, applicationArguments);
     } catch (Throwable ex) {
         // 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
     }

         //   (9)发布应用上下文就绪事件
     // 表示在前面一切初始化启动都没有问题的情况下,使用运行监听器
     // SpringApplicationRunListener持续运行配置好的应用上下文ApplicationContext,
     // 这样整个Spring Boot项目就正式启动完成了。
     try {
        listeners.running(context);
     } catch (Throwable ex) {
             // 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
             handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
     }
      //返回容器
     return context;
  }
}