文章目录

  • 1. 启动类
    • @SpringBootApplication
      • 1. @Configuration
      • 2. @EnableAutoConfiguration
      • 3. @ComponentScan
  • 2. 启动流程图
  • 3. 具体启动过程
    • 3.1 创建并构造SpringApplication对象
      • 1. 初始化资源加载器
      • 2. 初始化主要资源加载类集合并去重
      • 3. 得到当前WEB应用类型
      • 4. 设置应用上下文初始化器
      • 5. 设置监听器
      • 6. 得到主应用程序启动类
    • 3.2 调用SpringApplication对象的run方法
      • 1. 创建计时器,开始计时
      • 2. 配置系统属性(Headless)
      • 3. 初始化监听器
        • SpringApplicationRunListener监听器
      • 4. 调用监听方法starting
      • 5. 加载命令行的参数值
      • 6. 创建并配置应用环境
      • 7. 配置忽略Bean信息
      • 8. 打印Banner信息
      • 9. 创建应用上下文
        • 应用上下文对象实际类型
        • ClassPathBeanDefinitionScanner
        • AnnotatedBeanDefinitionReader
      • 10. 获取异常报告器
      • 11. 准备(配置)应用上下文
      • 12. 刷新应用上下文
      • 13. 刷新完成后的后置处理
      • 14. 停止计时
      • 15. 调用监听方法started
      • 16. 加载自定义初始化信息
      • 17. 调用监听方法running

1. 启动类

Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法。在main方法中使用SpringApplication.run方法启动SpringBoot应用项目。

@SpringBootApplication

@SpringBootApplication是Spring Boot的核心注解。它是一个组合注解,包含了一下三个注解:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan

如果不使用@SpringBootApplication注解,直接使用@Configuration、@EnableAutoConfiguration、@ComponentScan也能达到相同效果。

1. @Configuration

是做类似于spring xml 工作的注解,标注在类上,类似与以前的**.xml配置文件。

2. @EnableAutoConfiguration

SpringBoot自动装配需要的注解,会让SpringBoot根据类路径中的jar包依赖为当前项目进行自动装配。同时,它也是一个组合注解,包含:

  • @Import
  • @AutoConfigurationPackage
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

其中@Import注解导入了EnableAutoConfigurationImportSelector类,这类就是自动装配关键。

自动装配是SpringBoot的一大特色。

自动配置举例:

  • 添加了spring-boot-starter-web依赖,会自动添加Tomcat和SpringMVC的依赖,SpringBoot会对Tomcat和SpringMVC进行自动配置。

  • 添加了spring-boot-starter-data-jpa依赖,SpringBoot会自动进行JPA相关的配置。

3. @ComponentScan

@ComponentScan注解用于告诉Spring哪个packages的用注解标识的类,会被spring自动扫描并且装入bean容器。

SpringBoot默认会自动扫描@SpringBootApplication所在类的同级包以及下级包的Bean(如果为JPA项目还可以扫描标注@Entity的实体类),所以建议入口类放置在最外层包下。

如果需指定扫描路径,需在启动类上加@ComponentScan注解,如下

@SpringCloudApplication
@ComponentScan(value = "com.joker")
public class CoreApplication {public static void main(String[] args) {SpringApplication.run(CoreApplication.class, args);}
}

2. 启动流程图

3. 具体启动过程

springboot版本:2.2.2.RELEASE

springboot的启动过程包括:

  • 创建并构造SpringApplication对象
  • 调用SpringApplication对象的run方法

3.1 创建并构造SpringApplication对象

 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 初始化资源加载器,默认为nullthis.resourceLoader = resourceLoader;// 断言主要加载资源类不能为空Assert.notNull(primarySources, "PrimarySources must not be null");// 初始化主要资源加载类集合并去重this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 得到当前WEB应用类型this.webApplicationType = WebApplicationType.deduceFromClasspath();// 设置应用上下文初始化器并去重setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置监听器并去重setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 得到主应用程序启动类this.mainApplicationClass = deduceMainApplicationClass();}

1. 初始化资源加载器

默认为null

2. 初始化主要资源加载类集合并去重

3. 得到当前WEB应用类型

一共有三种类型:NONE、SERVLET、REACTIVE

4. 设置应用上下文初始化器

从"META-INF/spring.factories"文件读取key为ApplicationContextInitializer的实例名称集合并去重

5. 设置监听器

从"META-INF/spring.factories"文件读取key为ApplicationListener的实例名称集合并去重(共有11个监听器)

6. 得到主应用程序启动类

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

方法调用顺序,由此找到mian方法所在类

3.2 调用SpringApplication对象的run方法

run方法源码如下:

 public ConfigurableApplicationContext run(String... args) {// 创建计时器(任务执行观察者)StopWatch stopWatch = new StopWatch();// 开始计时stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();// 配置系统属性(Headless)configureHeadlessProperty();// 注册监听器SpringApplicationRunListeners listeners = getRunListeners(args);// 调用监听方法startinglisteners.starting();try {// 加载命令行的参数值ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 创建并配置应用环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 配置忽略Bean信息configureIgnoreBeanInfo(environment);// 打印banner图形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);}// 调用监听方法startedlisteners.started(context);// 执行自定义初始化callRunners(context, applicationArguments);}catch (Throwable ex) {// 异常处理handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {// 调用监听方法runninglisteners.running(context);}catch (Throwable ex) {// 异常处理handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}

1. 创建计时器,开始计时

创建一个StopWatch实例并执行start方法,这个类主要记录任务的执行时间

2. 配置系统属性(Headless)

配置系统属性java.awt.headless,意义不大,可以忽略。

Headless模式是在缺少显示屏、键盘或者鼠标时候的系统配置。

3. 初始化监听器

得到SpringApplicationRunListeners,内部持有:

  1. Log日志类

  2. SpringApplicationRunListener集合(里面只有一个监听器EventPublishingRunListener)

    SpringApplicationRunListener是一个接口,EventPublishingRunListener是接口的唯一实现类。

EventPublishingRunListener(事件发布运行监听器) 内部包含三个属性:

 private final SpringApplication application;private final String[] args;private final SimpleApplicationEventMulticaster initialMulticaster;

该监听器内含事件广播器SimpleApplicationEventMulticaster,主要用于广播(发布)事件。

SpringApplicationRunListener监听器

用于监听SpringApplication的run方法的执行,它有7种方法:

监听器方法 调用时间 广播的事件
starting run方法执行的时候立马调用 ApplicationStartingEvent
environmentPrepared ApplicationContext创建之前并且环境信息准备好的时候调用 ApplicationEnvironmentPreparedEvent
contextPrepared ApplicationContext创建好并且在source加载之前调用 ApplicationContextInitializedEvent
contextLoaded ApplicationContext创建并加载之后并在刷新之前调用 ApplicationPreparedEvent
started ApplicationContext已刷新且应用程序已启动,但自定义初始化信息尚未被调用时调用 ApplicationStartedEvent
running ApplicationContext已刷新并且所有自定义初始化信息都已被调用时调用 ApplicationReadyEvent
failed ApplicationContext创建过程中发生故障时调用 ApplicationFailedEvent

4. 调用监听方法starting

调用监听方法starting,广播ApplicationStartingEvent事件,触发相关的监听器(4个)

  • 获取到创建SpringApplication对象时设置的所有监听器(11个)
  • 筛选出其中监听ApplicationStartingEvent事件的那些监听器(4个),触发这些监听器

5. 加载命令行的参数值

解析在命令行中通过key=value输入的属性值,把他们封装到一个DefaultApplicationArguments类中

6. 创建并配置应用环境

创建用程序的环境Environment,并设置比如:环境信息,系统熟悉,输入参数和profile信息。

 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}
  • 创建环境对象
    创建环境对象,配置4个属性资源:servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment

  • 配置环境

    • 配置ConversionService(转换服务)
    • 配置PropertySources(属性资源)
    • 配置Profiles(环境),如dev、test、prod

    配置的内容包含:conversionService、activeProfiles等

  • 配置附加属性资源
    配置configurationProperties

  • 调用监听方法environmentPrepared

    调用监听方法environmentPrepared,广播ApplicationEnvironmentPreparedEvent事件,触发相关的监听器(7个)

  • 绑定环境到SpringApplication中

7. 配置忽略Bean信息


8. 打印Banner信息

9. 创建应用上下文

也可叫创建Spring容器。根据WebApplicationType来创建应用上下文对象。在构造方法中初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。

应用上下文对象实际类型

  • SERVLET: AnnotationConfigServletWebServerApplicationContext
  • REACTIVE:AnnotationConfigReactiveWebServerApplicationContext
  • 其他:AnnotationConfigApplicationContext

ClassPathBeanDefinitionScanner

BeanDefinition扫描器,主要作用:扫描带有bean候选者相关注解的类,生成对应的BeanDefinition

bean候选者相关注解:

  • @Component
  • @Repository
  • @Service
  • @Controller

AnnotatedBeanDefinitionReader

BeanDefinition读取器,主要作用:

  • 注册内置BeanPostProcessor

  • 注册相关BeanDefinition

10. 获取异常报告器

在文件META-INF\spring.factories中获取异常报告器集合(里面只有一个报告器:FailureAnalyzers)。

11. 准备(配置)应用上下文

也可叫 准备(配置)Spring容器。

主要步骤如下:

  • 为应用上下文设置环境信息environment

  • 为应用上下文设置转换服务ConversionService

  • 应用上下文初始化

    执行应用上下文的初始化。一共有7个初始化器,对应用上下文进行初始化

    这些初始化器主要作用是为上下文注入BeanFactoryPostProcessor集合、ApplicationListener集合等

  • 调用监听方法contextPrepared

    调用监听方法contextPrepared,广播ApplicationContextInitializedEvent事件,触发相关的监听器(2个)

  • 把SpringApplicationArguments、SpringBootBanner以单例形式注册到BeanFactory中

  • 加载资源配置,完成自动装配

    这里只是把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中。

  • 调用监听方法contextLoaded

    调用监听方法contextLoaded,广播ApplicationPreparedEvent事件,触发相关的监听器(5个)

12. 刷新应用上下文

刷新应用上下文。在这里真正加载bean到容器中。如果是web容器,会在onRefresh方法中创建一个Server并启动。

  • 准备刷新

    prepareRefresh()

    刷新上下文环境,初始化上下文环境,对系统的环境便利或者系统属性进行准备和校验

  • 获取刷新后的bean工厂

    obtainFreshBeanFactory()

    获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等。

    注意此处是获取新的,销毁旧的,这就是刷新的意义(Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。)

  • 准备bean工厂

    prepareBeanFactory(beanFactory)

    • 设置类加载器
    • 设置EL表达式解析器(Bean创建完成填充属性时使用)和属性注册解析器
    • 注册一些特殊的BeanPostProcessor(如:ApplicationContextAwareProcessor、ApplicationListenerDetector、)
    • 设置忽略自动装配的类(各种Aware接口的实现类)
    • 设置自动装配的类(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext)
    • 如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加动态织入功能
    • 添加默认环境相关Bean(environment,systemProperties,systemEnvironment)
  • 后处理bean工厂

    postProcessBeanFactory(beanFactory)

    允许在上下文子类中对 bean 工厂进行后置处理。

    在beanfactory加载完成所有的bean后,想修改其中某个bean的定义,或者对beanFactory做一些其他的配置,就可以在子类中对beanFactory进行后置处理(子类通过实现接口BeanFactoryPostProcessor来自定义后置处理)。

    后置处理器执行的时间是:在所有的beanDenifition加载完成之后,bean实例化之前执行。

  • 调用bean工厂后置处理器

    invokeBeanFactoryPostProcessors(beanFactory)

    调用在上下文中注册为bean的工厂处理器,执行方法:

    • BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
    • BeanFactoryPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
  • 注册bean后置处理器

    registerBeanPostProcessors(beanFactory)

    注册实现了BeanPostProcessor接口的bean。
    例如:

    • AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
    • RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
    • CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
  • 初始化消息源

    initMessageSource()

    初始化国际化工具类MessageSource。

  • 初始化应用事件广播器

    initApplicationEventMulticaster()

  • 刷新(初始化特殊的bean)

    onRefresh()

    这个方法在AbstractApplicationContext中没有实现,留给子类来初始化其他的Bean,是个模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情。

    SpringBoot项目在这个阶段完成:启动内置Web容器(如Tomcat),并初始化一些特殊的bean(如DataSource)。

    这阶段主要完成的事情:

    1. 初始化主题功能
    2. 启动SpringBoot的嵌入式Tomcat服务器
      1. 启动web容器
      2. 创建ServletContext
      3. 创建Listener
      4. 创建Filter
      5. 创建Servlet
    3. 初始化一些特殊的bean
  • 注册监听器

    registerListeners()

    注册监听器,并且广播earlyApplicationEvents,也就是早期的事件

  • 完成bean工厂初始化

    finishBeanFactoryInitialization(beanFactory)

    该方法会初始化所有剩余的非懒加载单例bean,并调用BeanPostProcessors。

    除了一些内部的 bean、实现了BeanFactoryPostProcessor 接口的 bean、实现了BeanPostProcessor 接口的 bean,其他的非懒加载单例bean都会在这个方法中被初始化,BeanPostProcessor的触发也是在这个方法中。

  • 完成刷新

    finishRefresh()

    通知生命周期处理器LifecycleProcessor完成刷新过程,同时发出ContextRefreshEvent通知别人

    refresh做完之后需要做的其他事情:

    • 清除上下文资源缓存(如扫描中的ASM元数据)
    • 初始化上下文的生命周期处理器,并刷新(找出Spring容器中实现了Lifecycle接口的bean并执行start()方法)。
    • 发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作

13. 刷新完成后的后置处理

上下文刷新完成之后的操作,调用afterRefresh方法。默认什么都不做,主要方便扩展。

14. 停止计时

15. 调用监听方法started

广播ApplicationStartedEvent事件。Spring启动结束,开始所有的监听器对象

16. 加载自定义初始化信息

加载自定义初始化信息,用于扩展,相当于开机启动。

此时会获取到ApplicationRunner、CommandLineRunner这两个接口类型的所有bean集合,循环调用每一个bean的run方法。

17. 调用监听方法running

广播ApplicationReadyEvent事件。应用启动完成,可以对外提供服务了。

SpringBoot启动加载过程相关推荐

  1. redis 启动加载mysql_Redis分析系列:启动加载过程

    从本篇文章开始(命名为Redis分析系列),将会通过分析Redis的源代码(以Redis 2.2.0 RC1为准),来对它的内部实现做一些探讨.本文主要介绍Redis启动加载过程,总体上可以分为如下几 ...

  2. jboss之启动加载过程详解(-)

    今天看了看jboss的boot.log和server.log日志,结合自己的理解和其他的资料,现对jboss的启动和加载过程做出如下总结: 本文以JBoss Application Server 4. ...

  3. springboot 启动加载数据库数据到redis缓存

    启动项目后, 加载数据库公共配置数据到redis中 import org.springframework.data.redis.core.RedisTemplate; import org.sprin ...

  4. springboot启动加载流程

    springboot 启动类有两大核心: 一个是注解@SpringBootApplication,一个是main方法里面的SpringApplication.run. 1.通过main方法 启动spr ...

  5. Linux启动加载过程解析

    启动第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬 ...

  6. springboot 启动加载数据 commandLineRunner

    项目启动时,我们需要加载一些数据或启动定时任务执行数据下载或同步,此时可以用到commandLineRunner类. @Component //被spring容器管理 @Order(value = 2 ...

  7. MongoDB大量集合启动加载优化原理

    背景 启动数据加载时间对于很多数据库来说是一个不容忽视的因素,启动加载慢直接导致数据库恢复正常服务的RTO时间变长,影响服务可用性.比如Redis,启动时要加载RDB和AOF文件,把所有数据加载到内存 ...

  8. springboot集成mybatis源码分析-启动加载mybatis过程(二)

    springboot集成mybatis源码分析-启动加载mybatis过程(二) 1.springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplicati ...

  9. 开机启动加载驱动过程中调用PostMessage函数出错

    今天在WINCE5.0+S3C2440系统调试检测出租车是否载客的驱动的时候遇到这样的问题: 发现在开机启动加载驱动过程中调用PostMessage函数时会导致调用的线程崩溃,比如如果下面的线程在创建 ...

最新文章

  1. 我挖掘Kafka底层原理!发现了它火爆宇宙的3个真相!
  2. Streams:深入理解Redis5.0新特性
  3. 【剑指offer】Q38:数字在数组中出现的次数
  4. NGINX的几个应用场景
  5. 深入理解JavaScript系列(4):立即调用的函数表达式
  6. 安全现状:从通杀到专杀
  7. [转]ActionScript 3.0入门:Hello World、文件读写、数据存储(SharedObject)、与JS互调
  8. Java的自动装箱与自动拆箱
  9. sqL编程篇(三) 游标与存储过程
  10. CDH 6 安装服务哈希验证失败 解决方法
  11. jquery-待办事列表-待整理
  12. 超越 YOLOv5 的目标检测开源项目又上新了
  13. 自定义控件实现(转)
  14. 11Linux_vmtools
  15. Tomcat服务器报错IOException: Broken pipe
  16. Matlab网格划分
  17. 如何用思维导图快速理解PMBOK-PMP第六版教材
  18. 技术揭秘QQ空间”自动转发不良信息
  19. 继暗影机器人跑路,守护者群管作者也宣布退网
  20. 网友自制的谷歌输入法皮肤及制作方法

热门文章

  1. android SeekBar
  2. 信用风险评分的原理及实现
  3. 如何确定数组中含有某个元素?
  4. android 震动Vibrator
  5. 手把手教你1小时快速建站
  6. 【云速建站】多语言站点集合
  7. AI还原“帝王相”,背后的技术真让人惊叹!
  8. 目标管理SMART原则PPT模板
  9. 数据库系统工程师(第一章)
  10. DIY 一个 Excel 版的子网计算器