SpringBoot启动原理

从一个SpringBoot启动类说起。
@SpringBootApplication
public class DemoApplication{
    public static void main(Stirng[] args){
        SpringApplication.run(DemoApplication.class, args);
    }
}
@SpringBootApplication是以下三个Annotation的复合:
  • @Configuration:SpringBoot启动类本身也是一个配置类。
  • @EnableAutoConfiguration:作为一个复合Annotation,其定义中最关键的是@Import(AutoConfigurationImportSelector.class),在AutoConfigurationImportSelector类中,通过调用SpringFactoriesLoader的方法从classpath中搜寻所有META-INF/spring.factories配置文件,将其中自动配置项通过反射实例化为对应IoC配置类,然后汇总为一个加载到IoC容器中。
  • @ComponentScan:自动扫描并加载符合条件的组件。

 SpringBoot应用的启动流程:

 1. SpringApplication.run()的运行会创建一个SpringApplication实例,在其初始化时会收集各种条件和回调接口,例如,判断是否为web类型、加载ApplicationContextInitializer和  ApplicationListener(这里用到了SpringFactoriesLoader类的方法)、推断并设置main方法的定义类。以下所有的this指针均指向SpringApplication实例。

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    //...
    this.webApplicationType = WebApplicationType.deduceFromClasspath();                             this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

 2. 进入run方法的逻辑中,通过SpringFactoriesLoader获得 SpringApplicationRunListeners的实例 listeners (其中封装了一个SpringApplicationRunListener集合),执行listeners.starting(),表示“SpringBoot应用开始执行!”。

SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();

 3. 创建Environment,配置其PropertySorce以及Profile。

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);

 在prepareEnvironment方法中执行了listeners的environmentPrepared方法,表示“SpringBoot应用的Environment准备好了!”。

listeners.environmentPrepared((ConfigurableEnvironment)environment);

 4. 创建ApplicationContext,这里会根据用户是否明确设置了applicationContextClass类型以及初始阶段的推断结果,决定当前的ApplicationContext类型。

context = this.createApplicationContext();

 配置ApplicationContext。

this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

 在prepareContext方法中设置了Environment,又调用了ApplicationContextInitializer的initialize方法对已经创建好的context做进一步的处理,然后执行listeners的contextPrepared方法,表示“SpringBoot应用的ApplicationContext准备好了!”。

private void prepareContext(//...) {
    context.setEnvironment(environment);
    this.postProcessApplicationContext(context);
    this.applyInitializers(context);
    listeners.contextPrepared(context);
    //...
}

 5. 最核心的一步:同样是在prepareContext方法中,将之前@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备好的context中,然后执行listeners 的contextLoaded方法,表示“SpringBoot应用的ApplicationContext装填完毕!”。

private void prepareContext(//...) {
    //...
    Set<Object> sources = this.getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    this.load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
}

 6. 执行refreshContext方法,最终调用的是ApplicationContext的refresh方法,完成IoC容器可用的最后一道工序。另外,这里还判断了一下是否需要添加ShutdownHook。

private void refreshContext(ConfigurableApplicationContext context) {
    this.refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException var3) {
        }
    }
}

 7. 执行afterRefresh方法,其实什么也没有做。

protected void afterRefresh(//...) {
}

 8. 执行listeners的started方法,表示“SpringBoot应用已经启动!”。

listeners.started(context);

 9. 查找ApplicationContext中是否注册有ApplicationRunner和CommandLineRunner,如果有,则执行它们。

this.callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    //...
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    //...
}

 10. 正常情况下,到这里就已经完成了 (如果整个过程出现异常,那么会有详细的异常处理类负责检测)。最后还有一个listeners的running方法可以进一步检测容器是否正常。

try {
    listeners.running(context);
    return context;
} catch (Throwable var9) {
    //...
    throw new IllegalStateException(var9);
}

 整个过程看起来冗长无比,但忽略其中的事件通知等逻辑,那么这个启动过程可以精简为:

  1. 初始化SpringApplication,收集各种条件和回调接口。
  2. 创建并配置Environment。
  3. 创建并初始化ApplicationContext,设置Environment,加载自动配置等。
  4. 更新ApplicationContext,完成最终程序启动。

原文地址:https://www.cnblogs.com/asleaf/p/12594628.html

时间: 2024-08-01 10:00:37

SpringBoot启动原理的相关文章

SpringBoot启动原理分析

用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对SpringBoot的启动流程略作记录. 此文的SpringBoot启动流程分析是基于SpringBoot 1.x的,SpringBoot 2.x的启动流程与1.x的略有不同,后续再进行补充分析. 核心注解@SpringBootApplication 每个SpringBoot应用,都有一个入口类,标注@Spri

SpringBoot启动原理解析

1. 启动任何一个Spring Boot项目,都会用到如下类 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 从上面代码可以看出,Annotation定义@SpringBootApplication和类定义SpringApplication.run是关键所在.

springboot之启动原理解析

前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplica

springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理

1.嵌入式Servlet容器自动配置原理 1.1 在spring-boot-autoconfigure-1.5.9.RELEASE.jar => springboot自动配置依赖 jar包下,EmbeddedServletContainerAutoConfiguration => 嵌入式servlet容器自动配置类 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplicatio

springboot之启动原理解析及源码阅读

原文地址:https://www.cnblogs.com/shamo89/p/8184960.html 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication //Annotation(注解)定义了(@SpringBootApplication) public class Application { public static void main(String[] args) { //类定义(SpringApplication.run

SpringBoot启动过程原理

最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理. 一.springboot的三种启动方式: 1.运行带有main方法的2.通过命令 Java -jar命令3.通过spring-boot-plugin的方式 二.springboot 启动时执行方法,有两种方式 第一种方式是用启动时的main方法加载静态方法. 另一种是用初始化注解@postconstruct 执行.(注意点必须void并且参数). 注意点:[1.@PostConstruct会先被执行,静

SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

SpringBoot启动机制(starter机制)核心原理详解

作者:MyBug 一.前言 使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程.本文的目的就是一步步分析springboot的启动过程,这次主要是分析springboot特性自动装配.那么首先带领大家回顾一下以往我们的web项目是如何搭建的,通常我们要搭建一个基于Spring的Web应用,我们需要做以下一些工作:pom文件中引入相关jar包,包括spring.springmvc.redis.mybaits.l

SpringBoot源码学习系列之启动原理简介

本博客通过debug方式简单跟一下Springboot application启动的源码,Springboot的启动源码是比较复杂的,本博客只是简单梳理一下源码,浅析其原理 为了方便跟源码,先找个Application类,打个断点,进行调试,如图所示: step into,run方法调用了SpringApplication的run方法 通过debug,Springboot启动过程,会先执行如下关键的构造函数 分析构造函数源码: public SpringApplication(ResourceL