springboot启动流程原理

简介: springboot启动流程原理

springboot的启动流程主要包括以下部分:

一、SpringBootApplication启动类

启动类的常见写法

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

需要重点关注的是@SpringBootApplication注解和SpringApplication.run(SpringmvcApplication.class, args)方法。

二、SpringApplication.run方法

1.实例化SpringApplication

SpringApplication.run(SpringmvcApplication.class, args)调用的方法;

//启动类调的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    //调的是下面的,参数是数组的run方法
    return run(new Class<?>[] { primarySource }, args);
}
//和上面的方法区别在于第一个参数是一个数组
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    //实际上new一个SpringApplication实例,调的是一个实例方法run()
    return new SpringApplication(primarySources).run(args);
}

判断当前项目类型

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    //断言primarySources不能为null,如果为null,抛出异常提示
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //启动类传入的Class
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断当前项目类型,有三种:NONE、SERVLET、REACTIVE
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //设置ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //设置监听器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //判断主类,初始化入口类
    this.mainApplicationClass = deduceMainApplicationClass();
}
//判断主类
private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

设置初始化器

从类路径中META-INF/spring.factories加载对应的配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。

//设置初始化器(Initializer),最后会调用这些初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));

//设置初始化器(Initializer),最后会调用这些初始化器
setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 这里的入参type就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // 使用Set保存names来避免重复元素
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 根据names来进行实例化
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    // 对实例进行排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 这里的入参type就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // 使用Set保存names来避免重复元素
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 根据names来进行实例化
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    // 对实例进行排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

设置监听器类。 主要的方式和设置初始化类一样。

整个流程:

总结

1、构造SpringApplication对象

主要判断容器类型是否为servlet、reactive还是none

2、获取ApplicationContextInitializer对象

从META-INF/spring.factories获取容器初始化需要的初始化对象

3、获取ApplicationListener对象

从META-INF/spring.factories获取监听器的配置类

2.执行run()方法

实例化后就是执行run()方法;

主要包括以下步骤:

  • 第一步:获取并启动监听器
  • 第二步:根据SpringApplicationRunListeners以及参数来准备环境
  • 创建Environment环境变量
  • 会查询系统变量,环境变量还有启动参数
  • 第三步:创建Spring容器
  • 第四步:Spring容器前置处理
  • 第五步:刷新容器
  • 将启动类作为配置类传给run()方法,作为spring容器的配置类
  • 第六步:Spring容器后置处理
  • 第七步:发出结束执行的事件
  • 第八步:执行Runners
  • 在springboot的启动过程中会执行ApplicationRunner和CommandLineRunner类型的bean
    1.获取Spring容器中的ApplicationRunner类型的Bean
    2.获取Spring容器中的CommandLineRunner类型的Bean
    3.执行它们的run()

会在springcontext创建之前就包environment环境变量准备好;

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);
        // 第二步:根据SpringApplicationRunListeners以及参数来准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
        Banner printedBanner = printBanner(environment);
        // 第三步:创建Spring容器
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 第四步:Spring容器前置处理
        prepareContext(context, environment, listeners, applicationArguments,printedBanner);
        // 第五步:刷新容器
        refreshContext(context);
     // 第六步:Spring容器后置处理
        afterRefresh(context, applicationArguments);
      // 第七步:发出结束执行的事件
        listeners.started(context);
        // 第八步:执行Runners
        this.callRunners(context, applicationArguments);
        stopWatch.stop();
        // 返回容器
        return context;
    }
    catch (Throwable ex) {
        handleRunFailure(context, listeners, exceptionReporters, ex);
        throw new IllegalStateException(ex);
    }
}

3.项目启动可选的初始化操作

  • 通过ApplicationRunner和CommandLineRunner
  • 通过InitializingBean注解
  • 通过监听事件来处理

参考资料

  1. SpringBoot启动流程是怎样的?:https://juejin.cn/post/6895341123816914958#heading-8
  2. SpringBoot 源码解析 (二)----- Spring Boot精髓:启动流程源码分析:https://www.cnblogs.com/java-chen-hao/p/11829344.html#_label0_0

todo

  1. 文章细节待补充待优化


目录
打赏
0
0
0
0
223
分享
相关文章
SpringBoot项目打war包流程
本文介绍了将Spring Boot项目改造为WAR包并部署到外部Tomcat服务器的步骤。主要内容包括:1) 修改pom.xml中的打包方式为WAR;2) 排除Spring Boot内置的Tomcat依赖;3) 添加Servlet API依赖;4) 改造启动类以支持WAR部署;5) 打包和部署。通过这些步骤,可以轻松地将Spring Boot应用转换为适合外部Tomcat服务器的WAR包。
160 64
SpringBoot项目打war包流程
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
49 12
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
63 0
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
81 17
springboot自动配置原理
spring boot 启动流程
Spring Boot 启动流程简介: 在使用 Spring Boot 之前,启动 Java Web 应用需要配置 Web 容器(如 Tomcat),并将应用打包放入容器目录。而使用 Spring Boot,只需运行 main() 方法即可启动 Web 应用。Spring Boot 的核心启动方法是 SpringApplication.run(),它负责初始化和启动应用上下文。 主要步骤包括: 1. **应用启动计时**:使用 StopWatch 记录启动时间。 2. **打印 Banner**:显示 Spring Boot 的 LOGO。 3. **创建上下文实例**:通过反射创建
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
SpringBoot整合Flowable【04】- 通过代码控制流程流转
本文介绍了如何使用Flowable的Java API控制流程流转,基于前文构建的绩效流程模型。首先,通过Flowable-UI导出模型文件并部署到Spring Boot项目中。接着,详细讲解了如何通过代码部署、启动和审批流程,涉及`RepositoryService`、`RuntimeService`和`TaskService`等核心服务类的使用。最后,通过实际操作演示了流程从部署到完成的全过程,并简要说明了相关数据库表的变化。本文帮助读者初步掌握Flowable在实际业务中的应用,后续将深入探讨更多高级功能。
126 0
SpringBoot整合Flowable【04】-  通过代码控制流程流转
SpringBoot整合Flowable【03】- 通过Flowable-UI体验一个简单流程
本文介绍了如何使用Flowable 7.0以下版本的flowable-ui进行流程建模、发布和执行。首先,通过解压并启动flowable-ui war包,访问http://localhost:8080/flowable-ui/idm/#/login登录系统。接着,创建并绘制一个简单的绩效流程模型,包含开始节点、任务节点(自评、上级评、隔级评)和结束节点,并为各节点分配处理人。然后,创建应用并发布绩效流程。最后,通过创建a、b、c三个用户分别完成各节点任务,演示了整个流程的执行过程。本文旨在帮助读者理解Flowable的基本操作和流程元素,后续将介绍通过Java代码控制流程的方法。
147 0
SpringBoot整合Flowable【03】- 通过Flowable-UI体验一个简单流程
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
198 14
|
4月前
|
SpringBoot自动装配的原理
在Spring Boot项目中,启动引导类通常使用`@SpringBootApplication`注解。该注解集成了`@SpringBootConfiguration`、`@ComponentScan`和`@EnableAutoConfiguration`三个注解,分别用于标记配置类、开启组件扫描和启用自动配置。
82 17
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等