【 SpringBoot 】- [SpringApplication] -- run(启动)

  • 前言

前一篇文章【 SpringBoot 】- [SpringApplication] -- 初始化 ,已经把 SpringApplication 创建完成,接下来本文将介绍启动过程:即 run() 方法的流程。

/**
*    SpringApplication.java
*/
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        // 撸起 run()
        return (new SpringApplication(primarySources)).run(args);
    }
  • 热身

老规矩,先安静下来,跟着下图默默的认一下路.......

 

 

  • 开车 -> SpringApplication.run()

public ConfigurableApplicationContext run(String... args) {
// 1⃣️ 创建 StopWatch(秒表) 对象,主要用于统计启动时长
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 2⃣️ 配置 headlessProperty(标题属性)
        this.configureHeadlessProperty();
// 3⃣️ 获取所有的运行监听器 SpringApplicationRunListeners,并启动
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
// 4⃣️ 创建应用参数对象 ApplicationArguments
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5⃣️ 传入监听器+应用参数,配置运行环境:执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
// 6⃣️ 打印 banner(横幅)
            Banner printedBanner = this.printBanner(environment);
// 7⃣️ 创建应用上下文(spring容器)
            context = this.createApplicationContext();
// 8⃣️ 获取 SpringBootExceptionReporter.class 下的异常报告器集合 exceptionReporters
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 9⃣️ 准备 spring 上下文:主要是调用所有初始化类的 initialize 方法
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// ? 刷新 spring 上下文,即初始化spring容器
            this.refreshContext(context);
// 1⃣️1⃣️ 后置处理 spring 上下文
            this.afterRefresh(context, applicationArguments);
// 1⃣️2⃣️ 停止秒表,统计启动时长
            stopWatch.stop();
// 1⃣️3⃣️ 打印 秒表banner 统计的容器启动时长
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
// 1⃣️4⃣️ 通知所有的监听器,容器启动完成
            listeners.started(context);
// 1⃣️5⃣️ 呼叫所有的 runners 让他们奔跑起来 --> 调用所有 runners 的 run()方法
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
// 1⃣️6⃣️ 运行所有的 listener,发布监听事件
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • 第3步 -> getRunListeners()

/**
 *    SpringApplication.java
 */
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }

·  如约的出现了 getSpringFactoriesInstances() 惊不惊喜,意不意外!不再过多赘述:

「1」传入参数 type=SpringApplicationRunListener.class,「2」获取文件 META-INF/spring.factories 中以 SpringApplicationRunListener 为key的所有 classNames,「3」并利用反射实例化所有的listener,返回 listeners集合 ,「4」把 listeners 传入构造方法创建 SpringApplicationRunListeners 对象。

「spring.factories」 文件内容如下:只有一个事件发布监听器

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

debug 如下

pass:因为在此之前(上一篇文章)已经初始化了 SpringApplication,即已经通过 getSpringFactoriesInstances() 加载过了spring.factories文件,所以 getSpringFactoriesInstances --> loadFactoryNames --> loadSpringFactories 缓存已经存在所有的 classNames,直接返回即可,然后根据 type=SpringApplicationRunListener.class 挑选出 names。

·  end:第3步的结果如下

 

  • 第7步 -> createApplicationContext()

/**
 *    SpringApplication.java
 */

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        // 根据不同的 webApplicationType 获取对应的容器class 即 ApplicationContext.class
        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);
            }
        }
        // 创建 ApplicationContext
        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

这里的demo创建的是默认的注解式配置容器 --> AnnotationConfigApplicationContext

 

 

持续更新.......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值