[springboot]springboot启动流程[通俗易懂]

[springboot]springboot启动流程[通俗易懂]SpringBoot程序有一个入口,就是main方法。main里面调用SpringApplication.run()启动整个SpringBoot程序,该方法所在类需要使用@SpringBootApplication复合注解。其中需要关注的是:@SpringBootApplication注解其实是包含了三个注解:@EnableAutoConfiguration:SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置。简单概括一下就是,是借助@Import的帮助,将所有符合自动配

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Spring Boot程序有一个入口,就是main方法。main里面调用SpringApplication.run()启动整个Spring Boot程序,该方法所在类需要使用@SpringBootApplication复合注解。

1、@SpringBootApplication注解的组成

@EnableAutoConfiguration

@EnableAutoConfiguration是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器

在这个注解中,最重要的是它导入了一个类EnableAutoConfigurationImportSelector,它是一个ImportSelector接口的实现类

Spring Boot在启动时,在classpath下所有的META-INF/spring.factories文件中根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfig.EnableAutoConfiguration作为查找的Key,获得对应的一组@Configuration类,并将其封装到一个List中返回。(spring.factories是一个典型的java properties文件,只不过Key和Value都是Java类型的完整类名)

通过 filter 过滤掉当前环境不需要自动装配的类,比如没有集成RabbitMQ,就不需要,或者有的条件@Conditional不满足也不需要自动装配

将需要自动装配的全路径类名注册到 SpringIOC 容器,自此 SpringBoot 自动装配完成!

@SpringBootConfiguration

该注解作用就是将当前的类作为一个JavaConfig,然后触发注解@EnableAutoConfiguration和@ComponentScan的处理,本质上与@Configuration注解没有区别。

@ComponentScan

@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

2、SpringBoot启动流程

1、SpringBoot启动的时候,会构造一个SpringApplication的实例,然后调用这个实例的run方法,在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:

  1. 把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数.
  2. 判断是否是web程序,并设置到webEnvironment的boolean属性中.
  3. 创建并初始化ApplicationInitializer,设置到initializers属性中 。
  4. 创建并初始化ApplicationListener,设置到listeners属性中 。
  5. 初始化主类mainApplicatioClass。

源代码:

private void initialize(Object[] sources) { 
   
      if (sources != null && sources.length > 0) { 
   
          //把sources设置到SpringApplication的sources属性中,目前只是一个MyApplication类对象
        this.sources.addAll(Arrays.asList(sources)); 
      }
          //判断是否是web程序,并设置到webEnvironment的boolean属性中
      this.webEnvironment = deduceWebEnvironment(); 
          //找出所有的初始化器,默认有5个,设置到initializers属性中 。
      setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
          //找出所有的应用程序监听器,默认有9个,设置到listeners属性中 。
      setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
          //找出运行的主类(main class)
      this.mainApplicationClass = deduceMainApplicationClass();
    }

2、SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:

  1. 构造一个StopWatch计时器,用来记录SpringBoot的启动时间 。
  2. 获取SpringApplicationRunListeners并封装到SpringApplicationRunListeners中启动,用于监听run方法的执行。
  3. 创建并初始化ApplicationArguments,获取run方法传递的args参数。
  4. 创建并初始化ConfigurableEnvironment(环境配置)。
  5. 打印banner和版本。
  6. 构造Spring容器(ApplicationContext)上下文。
  7. SpringApplicationRunListeners发布finish事件。
  8. StopWatch计时器停止计时,日志打印总共启动的时间。
  9. 发布SpringBoot程序已启动事件(started())
  10. 调用ApplicationRunner和CommandLineRunner
  11. 最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了(running())
public ConfigurableApplicationContext run(String... args) { 
   
    // 创建一个StopWatch实例,用来记录SpringBoot的启动时间
 StopWatch stopWatch = new StopWatch();
 stopWatch.start();
 ConfigurableApplicationContext context = null;
 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
 configureHeadlessProperty();
    // 通过SpringFactoriesLoader加载listeners:比如EventPublishingRunListener
 SpringApplicationRunListeners listeners = getRunListeners(args);
    // 发布SprintBoot启动事件:ApplicationStartingEvent
 listeners.starting();
 try { 
   
  ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     // 创建和配置environment,发布事件:SpringApplicationRunListeners#environmentPrepared
  ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  configureIgnoreBeanInfo(environment);
     // 打印SpringBoot的banner和版本
  Banner printedBanner = printBanner(environment);
     // 创建对应的ApplicationContext:Web类型,Reactive类型,普通的类型(非Web)
  context = createApplicationContext();
  exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    new Class[] { 
    ConfigurableApplicationContext.class }, context);
     // 准备ApplicationContext,Initializers设置到ApplicationContext后发布事件:ApplicationContextInitializedEvent
     // 打印启动日志,打印profile信息(如dev, test, prod)
     // 调用EventPublishingRunListener发布ApplicationContext加载完毕事件:ApplicationPreparedEvent
  prepareContext(context, environment, listeners, applicationArguments, printedBanner);
     // 最终会调用到AbstractApplicationContext#refresh方法,实际上就是Spring IOC容器的创建过程,并且会进行自动装配的操作
     // 以及发布ApplicationContext已经refresh事件,标志着ApplicationContext初始化完成
  refreshContext(context);
     // hook方法
  afterRefresh(context, applicationArguments);
     // stopWatch停止计时,日志打印总共启动的时间
  stopWatch.stop();
  if (this.logStartupInfo) { 
   
   new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  }
     // 发布SpringBoot程序已启动事件ApplicationStartedEvent
  listeners.started(context);
     // 调用ApplicationRunner和CommandLineRunner
  callRunners(context, applicationArguments);
 }
 catch (Throwable ex) { 
   
  handleRunFailure(context, ex, exceptionReporters, listeners);
  throw new IllegalStateException(ex);
 }

 try { 
   
     // 最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了
  listeners.running(context);
 }
 catch (Throwable ex) { 
   
  handleRunFailure(context, ex, exceptionReporters, null);
  throw new IllegalStateException(ex);
 }
 return context;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/171209.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 图形的光栅化_简述图像的采样和量化过程

    图形的光栅化_简述图像的采样和量化过程在前面的学习中,我们已经可以通过MVP变换,把摄像机观测的物体都压缩成了一个标准立方体,接下来我们要做的是把这个标准立方体绘制到屏幕(Screen)上何为屏幕?一个二维数组,每个元素称之为像素(pixel,pictureelement的缩写),例如我们常说的屏幕分辨率1920*1080,就是说有这么些个像素。屏幕是一个典型的光栅成像设备。光栅(Raster)在德语中就是屏幕的意思,光栅化(Rasterize,名变动)就是把东西画在屏幕上。像素,最小单位,像素内的颜色可以用rgba来定义,一

    2022年8月30日
    1
  • navicat永久激活码最新2021【在线注册码/序列号/破解码】

    navicat永久激活码最新2021【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    149
  • 时滞模型的matlab编程_如何用matlab仿真

    时滞模型的matlab编程_如何用matlab仿真Matlab仿真含时滞多智体一致性分析,附代码Matlab仿真含时滞多智体一致性分析,附代码Matlab仿真含时滞多智体一致性分析,附代码系统结构如下图所示:clear;clc;%2014_多智能体网络的一致性问题研究_纪良浩%此为Paper中的示例代码%例2.1:A=[0,0,0.1,0,0;0.1,0,0,0,0;0,0.15,0,0…

    2022年10月1日
    0
  • win10pycharm双击无响应_pycharm打不开了怎么办

    win10pycharm双击无响应_pycharm打不开了怎么办Windows10更新升级之后,Pycharm打不开了,经过了各种方法尝试,最终重装了微软的VC程序,问题即可解决。

    2022年8月26日
    8
  • mediumtext_text长度不够用,改为mediumtext感觉 又太大,有没什么方法?

    mediumtext_text长度不够用,改为mediumtext感觉 又太大,有没什么方法?楼主先要搞清楚,text和longtext这些都是可变长度的字段类型.这是phpMyAdmin里的说明:text:最多存储65535(2^16-1)字节的文本字段,存储时在内容前使用2字节表示内容的字节数.longtext:最多存储4294967295字节即4GB(2^32-1)的文本字段,存储时在内容前使用4字节表示内容的字节数.也就是说,你在longtext类型的字段里只存1个字符,占用空…

    2022年5月1日
    79
  • pig用法_animals

    pig用法_animals1.pig运行模式本地模式:pig-xlocal直接访问本地磁盘集群模式:pig或者pig-xmapreduce2.piglatin交互帮助信息help上传本地文件到

    2022年8月4日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号