SpringBoot启动流程SpringApplication准备阶段源码分析

下面就详细讲解一下“SpringBoot启动流程SpringApplication准备阶段源码分析”的完整攻略。SpringBoot启动流程可以分为准备阶段、运行阶段、关闭阶段三个阶段,而本篇主要介绍SpringApplication的准备阶段。

SpringBoot启动流程简介

SpringBoot启动流程包括如下三个阶段:

  1. 准备阶段:包括ApplicationContext的初始化、Environment的初始化等。
  2. 运行阶段:包括@Configuration、@SpringBootApplication加载实例化、自定义监听器的加载、加载web容器等。
  3. 关闭阶段:容器的销毁、自定义销毁器的调用等。

在三个阶段中,准备阶段是SpringBoot启动的基础。其中,SpringApplication负责整个启动流程的控制。

SpringApplication准备阶段源码分析

1. run方法

SpringApplication的主要方法是run方法。当我们在Main方法中启动SpringBoot时,SpringApplication的run方法会被执行。

在这个方法中,SpringApplication会先创建一个SpringApplicationRunListeners对象,并调用它的starting方法。

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        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;
}

2. prepareEnvironment方法

prepareEnvironment方法是准备环境变量的过程,即将ConfigurableEnvironment对象的属性设置好,后续创建IOC容器和相关环境时需要用到。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    configurePropertySources(environment, applicationArguments.getSourceArgs());
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

在这个方法中,首先使用getOrCreateEnvironment方法,获取或者创建ConfigurableEnvironment对象。然后通过方法configureEnvironment和configurePropertySources对ConfigurableEnvironment进行初始化。这些方法里面设置了一些常用的环境配置,比如设置环境的名称、激活的profiles、加载配置文件等等。最后,SpringApplication会将ConfigurableEnvironment转换成Environment对象,将其放到Environment中,以备后续使用。

3. configureHeadlessProperty方法

configureHeadlessProperty方法用于设置系统参数java.awt.headless的值,默认值为:System.getProperty("java.awt.headless", Boolean.FALSE.toString())。

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

4. configureIgnoreBeanInfo方法

configureIgnoreBeanInfo方法设置了系统参数spring.beaninfo.ignore的值,用于禁止Spring加载一些bean信息,加快Spring启动速度。

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
    if (this.beanInfoFactories.isEmpty()) {
        System.setProperty("spring.beaninfo.ignore", "true");
    }
    else {
        for (BeanInfoFactory beanInfoFactory : this.beanInfoFactories) {
            BeanInfoUtils.registerBeanInfo(beanInfoFactory);
        }
    }
}

5. getRunListeners方法

getRunListeners方法是获取SpringApplicationRunListeners对象的方法,这里会通过Spring Factories的方式,获取所有SpringApplicationRunListener的实现。

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

之后,SpringApplication会先调用SpringApplicationRunListeners的starting方法,并执行所有SpringApplicationRunListener的starting方法。

public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

至此,SpringApplication的准备阶段就已经完成了。接下来就是SpringApplication的运行阶段和关闭阶段。在这个过程中,SpringApplication会初始化Springboot的配置,并在ApplicationContext中启动所有的bean,为我们提供便捷的web服务。

代码示例1:SpringApplication的基本使用

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

代码示例2:多环境配置SpringApplication的使用

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setDefaultProperties(Collections.singletonMap("server.port", "8083"));
        app.run(args);
    }
}

以上简要地介绍了SpringBoot启动流程SpringApplication的准备阶段源码分析以及两个代码示例。希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot启动流程SpringApplication准备阶段源码分析 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • Java实现文件上传服务器和客户端

    下面从服务器和客户端两个角度,分别讲解Java实现文件上传的完整攻略。 一、服务器方案 1.1 前置准备 首先,我们需要引入Java的文件上传相关依赖包:commons-fileupload和commons-io。这两个包的作用是支持多种文件上传方式,并且后者还提供了一些方便的工具类来处理文件操作。 引入依赖参考pom.xml文件配置: <depend…

    Java 2023年5月20日
    00
  • angular实现input输入监听的示例

    下面我将向你详细讲解如何使用Angular实现input输入监听的示例。 1. 为input添加ngModel指令 首先,我们需要在HTML页面中给input元素添加ngModel指令,利用双向绑定机制将输入的内容与组件中的属性相绑定,从而实现输入监听。 示例代码如下: <input type="text" [(ngModel)]=…

    Java 2023年6月15日
    00
  • 常见的Java代码混淆工具有哪些?

    常见的Java代码混淆工具有以下几种: ProGuard: ProGuard 是一款开源的Java代码混淆工具,通过删除未使用的类、字段、方法和属性,重命名它们,使得反编译后的代码难以阅读和理解。使用方法如下: 1.1. 首先下载并安装 ProGuard 工具,可以从官方网站 https://sourceforge.net/projects/proguard…

    Java 2023年5月11日
    00
  • Java实现经典游戏飞机大战-I的示例代码

    非常感谢您对“Java实现经典游戏飞机大战-I的示例代码”的关注。 下面,我将为大家详细讲解如何实现这个示例代码,并提供两个示例说明。 1. 初步了解示例代码 首先,您需要了解示例代码的基本结构和所包含的类: Main 类:程序的启动入口,用于初始化并启动游戏。 GameFrame 类:游戏窗口,包含了游戏的整个界面,处理用户的输入和绘制游戏元素。 Game…

    Java 2023年5月23日
    00
  • Java经典面试题最全汇总208道(三)

    针对“Java经典面试题最全汇总208道(三)”的攻略,我将会进行详细的讲解,包括其中每个问题的答案和解释。 标题 Java经典面试题最全汇总208道(三) 代码块 下面是一道比较常见的Java面试题: public class Test{ public static void main(String[] args) { String str1 = new …

    Java 2023年5月23日
    00
  • Java Set接口及常用实现类总结

    Java Set接口及常用实现类总结 Set接口概述 Set接口是Collection接口的子接口,它是一个无序、不重复元素集。Set接口有以下特点: 不允许存储重复的元素; 没有定义特定的迭代顺序; 它是一种集合,因此它不会维护某个元素的插入顺序。 Set接口常用方法 方法名 描述 boolean add(E e) 添加一个元素到Set中 boolean …

    Java 2023年5月19日
    00
  • ANGULARJS中用NG-BIND指令实现单向绑定的例子

    下面我将详细讲解关于 ANGULARJS 中使用 ng-bind 指令实现单向绑定的攻略,主要分为以下几个方面。 什么是 ng-bind 指令? ng-bind 是 ANGULARJS 框架中用于将数据值绑定到 HTML 元素中的指令,它用于在模板中动态绑定数据,可以通过变化自动更新绑定数据的值,实现实时更新数据,具体用法如下: <div ng-bin…

    Java 2023年6月15日
    00
  • SpringBoot web开发源码深入分析

    SpringBoot是一个基于Spring框架的快速开发框架,其中的web开发模块封装了大量方便易用的API,可以帮助我们快速进行web应用的开发。本篇文章主要讲解SpringBoot的web开发模块的源码实现,希望通过深入分析的方式,让读者对SpringBoot有更全面的理解和应用。 1. 简介 SpringBoot的web开发源码分析主要包含以下几个方面…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部