SpringBoot启动流程总结

7 篇文章 0 订阅

1.导语

//以下是一个SpringBoot应用的标准入口:
public static void main(String[] args) {
    SpringApplication.run(TestApplication.class, args);
}
 
//SpringApplication.run 内部是这样的:先创建一个 SpringApplication 对象,然后调用他的run方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
}

 所以想要了解清楚 SpringBoot 启动流程,相当于了解 SpringApplication 的 构造方法 和 run方法。

 

2.构造方法详解

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
 
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
 
    // 判断应用类型,会有三种情况:
    // NONE:非web应用
    // SERVLET:普通web应用
    // REACTIVE:响应式web应用
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
 
    // 从 META-INF/spring.factories 文件中获取如下内容
    // 获取 注册初始化器:在 run 方法中的 createBootstrapContext(); 里会被使用
    this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    // 获取 容器初始化器:在 run 方法中的 prepareContext( ... ); 里会被使用
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 获取 监听器:在 run 方法中 listeners.xxx 时被使用
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
 
    this.mainApplicationClass = deduceMainApplicationClass();
}

 

3.run方法详解

public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
 
    // 第一步:创建监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
 
    // 发布事件:开始启动
    listeners.starting(bootstrapContext, this.mainApplicationClass);
 
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
 
        // 第二步:准备环境变量
        // 把一系列设置整合成 environment,包括 系统变量、JVM参数、启动参数(args)、配置文件(application、bootstrap等)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
 
        Banner printedBanner = printBanner(environment);
 
        // 第三步:创建空容器
        // 根据 new 时判断的 web类型(webApplicationType),创建对应类型的容器
        context = createApplicationContext();
 
        context.setApplicationStartup(this.applicationStartup);
 
        // 第四步:准备容器
        // 把前面准备的东西注入进去,包括 环境变量(environment)、事件监听器(listeners)、启动参数(applicationArguments)
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
 
        // 第五步:启用容器
        // 解析@SpringBootApplication注解,加载自动配置类
        // 进行Bean的扫描、加载、实例化、依赖注入
        // 如果是Web应用,会启动一个内嵌式的Web服务器比如Tomcat
        refreshContext(context);
 
        // 容器初始化后的操作,是个空方法,要使用需要继承并重写
        afterRefresh(context, applicationArguments);
 
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
 
        // 发布事件:已启动
        listeners.started(context, timeTakenToStartup);
 
        // 执行启动后的自定方法:
        // 实现 ApplicationRunner、CommandLineRunner 接口
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        if (ex instanceof AbandonedRunException) {
            throw ex; 
        }
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    try {
        // 检查应用是否还在运行
        if (context.isRunning()) {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            // 发布事件:准备就绪
            listeners.ready(context, timeTakenToReady);
        }
    }
    catch (Throwable ex) {
        if (ex instanceof AbandonedRunException) {
            throw ex;
        }
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    // 返回Bean容器
    return context;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yfeil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值