SpringBoot 之启动流程详解

 更新时间:2023年04月24日 09:08:04   作者:这堆干货有点猛  
SpringBoot 是一个基于 Spring 框架的快速开发框架,旨在简化 Spring 应用程序的开发和部署。在本文中,我们将深入分析 SpringBoot 启动过程的源代码,并提供必要的解释和说明

SpringBoot启动过程简介

SpringBoot应用程序的启动过程可以分为以下几个步骤:

  • 加载应用程序上下文
  • 扫描应用程序中的所有组件
  • 自动配置应用程序环境
  • 启动嵌入式Web服务器

在下面的章节中,我们将逐一分析这些步骤的源代码。

加载应用程序上下文

SpringBoot 应用程序的上下文是一个包含所有应用程序组件的容器。在启动过程中,SpringBoot 会加载并初始化这个容器。

这个步骤的源代码在SpringApplication类中。具体来说,SpringApplication类的run方法是这个过程的入口点。在这个方法中,Spring Boot会通过调用createApplicationContext方法来创建应用程序上下文。

下面是createApplicationContext方法的源代码:

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Unable to create a default ApplicationContext, " +
                    "please specify an ApplicationContextClass", ex);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

在这个方法中,SpringBoot 会根据应用程序类型(Servlet或Reactive)选择合适的上下文类。然后,它会使用 Java 反射机制来实例化这个类并返回一个可配置的应用程序上下文对象。

扫描应用程序中的所有组件

在上一步中,SpringBoot创建了应用程序上下文。在这一步中,SpringBoot会扫描应用程序中的所有组件并将它们注册到应用程序上下文中。

这个步骤的源代码在SpringApplication类中的scan方法中。具体来说,在这个方法中,SpringBoot 会创建一个SpringBootBeanDefinitionScanner对象,并使用它来扫描应用程序中的所有组件。

下面是scan方法的源代码:

private void scan(String... basePackages) {
    if (ObjectUtils.isEmpty(basePackages)) {
        return;
    }
    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
            this.includeFilters, this.excludeFilters, this.resourceLoader);
    scanner.setResourceLoader(this.resourceLoader);
    scanner.setEnvironment(this.environment);
    scanner.setIncludeAnnotationConfig(this.useAnnotatedConfig);
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return getExcludeClassNames().contains(className);
        }
    });
    for (String basePackage : basePackages) {
        scanner.findCandidateComponents(basePackage).forEach(this.componentDefinitions::add);
    }
}

在这个方法中,SpringBoot 会创建一个ClassPathScanningCandidateComponentProvider对象,并使用它来扫描应用程序中的所有组件。这个对象会扫描指定包路径下的所有类,并将它们转换为 Spring 的 Bean 定义。这些 Bean 定义将被注册到应用程序上下文中。

自动配置应用程序环境

在上一步中,SpringBoot将应用程序中的所有组件注册到应用程序上下文中。在这一步中,SpringBoot将自动配置应用程序环境,包括配置数据源、事务管理器、JPA等。

这个步骤的源代码在SpringApplication类中的configureEnvironment方法中。在这个方法中,Spring Boot会创建一个SpringApplicationRunListeners对象,并使用它来配置应用程序环境。

下面是configureEnvironment方法的源代码:

private void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addCommandLineProperties) {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        environment.getPropertySources().addLast(new CommandLinePropertySource(applicationArguments));
    }
    this.listeners.environmentPrepared(environment);
    if (this.logStartupInfo) {
        this.logStartupInfo(environment);
    }
    ConfigurationPropertySources.attach(environment);
    Binder.get(environment).bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(this.sources));
    if (!this.isCustomEnvironment) {
        EnvironmentConverter.configureEnvironment(environment, this.deduceEnvironmentClass());
    }
    this.listeners.environmentPrepared(environment);
}

在这个方法中,SpringBoot 会创建一个ApplicationArguments对象,并将其转换为一个命令行属性源。然后,它会调用listeners中的environmentPrepared方法来通知应用程序环境已经准备好了。随后,SpringBoot 会绑定属性源到应用程序环境中,并调用listeners中的environmentPrepared方法来通知应用程序环境已经准备好了。

启动嵌入式Web服务器

在上一步中,SpringBoot 将应用程序环境自动配置完成。在这一步中,SpringBoot 将启动嵌入式Web服务器,以便应用程序能够提供 Web 服务。

这个步骤的源代码在SpringApplication类中的run方法中。具体来说,在这个方法中,SpringBoot 会根据应用程序类型(Servlet或Reactive)选择合适的嵌入式Web服务器,并使用它来启动应用程序。

下面是run方法的源代码:

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;
}

在这个方法中,SpringBoot 会使用一个StopWatch对象来计算应用程序启动时间。然后,它会调用listeners中的starting方法来通知应用程序即将启动。接着,SpringBoot 会准备应用程序环境,并使用它来创建应用程序上下文。随后,SpringBoot 会调用listeners中的started方法来通知应用程序已经启动。最后,SpringBoot 会调用callRunners方法来运行所有的CommandLineRunnerApplicationRunner组件。

总结

在本文中,我们深入分析了 SpringBoot 应用程序的启动过程的源代码。我们了解了 SpringBoot 如何加载应用程序上下文、扫描应用程序中的所有组件、自动配置应用程序环境以及启动嵌入式Web服务器。这些步骤的源代码展示了 SpringBoot 如何简化应用程序的开发和部署。

以上就是SpringBoot 之启动流程详解的详细内容,更多关于SpringBoot启动流程的资料请关注脚本之家其它相关文章!

相关文章

  • Java接口操作(继承父类并实现多个接口)

    Java接口操作(继承父类并实现多个接口)

    这篇文章主要介绍了Java接口操作(继承父类并实现多个接口),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • Java NIO实现群聊系统

    Java NIO实现群聊系统

    这篇文章主要为大家详细介绍了Java NIO实现群聊系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 【IntelliJ IDEA】Maven构建自己的第一个Java后台的方法

    【IntelliJ IDEA】Maven构建自己的第一个Java后台的方法

    本篇文章主要介绍了Maven构建自己的第一个Java后台的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Springboot整合kafka的示例代码

    Springboot整合kafka的示例代码

    这篇文章主要介绍了Springboot整合kafka的示例代码,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • Java多线程 实例解析

    Java多线程 实例解析

    这篇文章主要介绍了Java多线程 实例解析,需要的朋友可以参考下
    2017-04-04
  • Spring Boot Jar 包部署脚本的实例讲解

    Spring Boot Jar 包部署脚本的实例讲解

    在本篇文章里小编给大家整理的是一篇关于Spring Boot Jar 包部署脚本的实例讲解内容,对此有兴趣的朋友们可以跟着学习下。
    2021-12-12
  • SpringBoot2实现MessageQueue消息队列

    SpringBoot2实现MessageQueue消息队列

    本文主要介绍了 SpringBoot2实现MessageQueue消息队列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Mybatis调用存储过程的案例

    Mybatis调用存储过程的案例

    这篇文章主要介绍了Mybatis如何调用存储过程,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 详解RabbitMq如何做到消息的可靠性投递

    详解RabbitMq如何做到消息的可靠性投递

    这篇文章主要为大家介绍了RabbitMq如何做到消息的可靠性投递,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Java中的ArrayList底层源码分析

    Java中的ArrayList底层源码分析

    这篇文章主要介绍了Java中的ArrayList底层源码分析,通过下标读取元素的速度很快,这是因为ArrayList底层基于数组实现,可以根据下标快速的找到内存地址,接着读取内存地址中存放的数据,需要的朋友可以参考下
    2023-12-12

最新评论