文章目录

  • SpringBootApplication注解
  • 自动配置核心类SpringFactoriesLoader
  • 整体启动流程
  • 初始化SpringApplication类
  • 执行核心run方法

SpringBootApplication注解

不从注解讲起都是耍流氓@SpringBootApplication注解@SpringBootApplication是一个复合注解,它由三个注解组成。

@SpringBootConfiguration(打开是@Configuration):表明这是一个Java配置类。

@EnableAutoConfiguration:自动配置注解,会将所有符合自动配置条件的@Configuration 配置加载到 IOC 容器。

@ComponentScan:扫描注解,自动扫描符合条件的组件(@Service、@Component)或者 bean 定义,记载到 IOC 容器中。


自动配置核心类SpringFactoriesLoader

上面在说@EnableAutoConfiguration的时候有说META-INF下的spring.factories文件,那么这个文件是怎么被spring加载到的呢,其实就是SpringFactoriesLoader类。SpringFactoriesLoader是一个供Spring内部使用的通用工厂装载器,SpringFactoriesLoader里有两个方法,

// 加载工厂类并实例化
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {}
// 加载工厂类的类名
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {}

在这个SpringBoot应用启动过程中,SpringFactoriesLoader做了以下几件事:

  1. 加载所有META-INF/spring.factories中的Initializer
  2. 加载所有META-INF/spring.factories中的Listener
  3. 加载EnvironmentPostProcessor(允许在Spring应用构建之前定制环境配置)接下来
  4. 加载Properties和YAML的PropertySourceLoader(针对SpringBoot的两种配置文件的加载器)
  5. 各种异常情况的FailureAnalyzer(异常解释器)
  6. 加载SpringBoot内部实现的各种AutoConfiguration
  7. 模板引擎TemplateAvailabilityProvider(如Freemarker、Thymeleaf、Jsp、Velocity等)

总得来说,SpringFactoriesLoader和@EnableAutoConfiguration配合起来,整体功能就是查找spring.factories文件,加载自动配置类。


整体启动流程

在我们执行入口类的main方法之后,运行SpringApplication.run,后面new了一个SpringApplication对象,然后执行它的run方法。

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {return new SpringApplication(sources).run(args);
}

初始化SpringApplication类

创建一个SpringApplication对象时,会调用它自己的initialize方法

private void initialize(Object[] sources) {if (sources != null && sources.length > 0) {this.sources.addAll(Arrays.asList(sources));}// 根据标志类javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext是否存在,判断是否是web环境this.webEnvironment = deduceWebEnvironment();// 通过SpringFactoriesLoader,获取到所有META-INF/spring.factories中的ApplicationContextInitializer,并实例化setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 通过SpringFactoriesLoader,获取到所有META-INF/spring.factories中的ApplicationListener,并实例化setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 获取执行当前main方法的类,也就是启动类this.mainApplicationClass = deduceMainApplicationClass();
}

执行核心run方法

初始化initialize方法执行完之后,会调用run方法,开始启动SpringBoot。

public ConfigurableApplicationContext run(String... args) {// 启动任务执行的时间监听器StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;// 设置系统java.awt.headless属性,确定是否开启headless模式(默认开启headless模式)configureHeadlessProperty();// 通过SpringFactoriesLoader,获取到所有META-INF/spring.factories下的SpringApplicationRunListeners并实例化SpringApplicationRunListeners listeners = getRunListeners(args);// 开始广播启动listeners.started();try {// 创建SpringBoot默认启动参数对象ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 根据启动参数创建并配置Environment(所有有效的配置,如Profile),并遍历所有的listeners,广播启动环境已准备ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);// 打印启动图案Banner printedBanner = printBanner(environment);// 根据标志类(上面有提到过),创建对应类型的ApplicationContextcontext = createApplicationContext();// 创建异常解析器(当启动失败时,由此解析器处理失败结果)analyzers = new FailureAnalyzers(context);// 准备Spring上下文环境// 在这个方法中,主要完成了以下几件事://  1、设置SpringBoot的环境配置(Environment)//  2、注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader//  3、加载ApplicationContextInitializer初始化器,并进行初始化//  4、统一将上面的Environment、BeanNameGenerator、ResourceLoader使用默认的Bean注册器进行注册prepareContext(context, environment, listeners, applicationArguments,printedBanner);// 注册一个关闭Spring容器的钩子refreshContext(context);// 获取当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法// ApplicationRunner和CommandLineRunner功能基本一样,在Spring容器启动完成时执行,唯一不同的是ApplicationRunner的run方法入参是ApplicationArguments,而CommandLineRunner是String数组afterRefresh(context, applicationArguments);// 通知所有listener,Spring容器启动完成listeners.finished(context, null);// 停止时间监听器stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}return context;} catch (Throwable ex) {// 启动有异常时,调用异常解析器解析异常信息,根据异常级别,判断是否退出Spring容器handleRunFailure(context, listeners, analyzers, ex);throw new IllegalStateException(ex);}
}
  1. 首先遍历执行所有通过SpringFactoriesLoader,在当前classpath下的META-INF/spring.factories中查找所有可用的SpringApplicationRunListeners并实例化。调用它们的starting()方法,通知这些监听器SpringBoot应用启动。
  2. 创建并配置当前SpringBoot应用将要使用的Environment,包括当前有效的PropertySource以及Profile。
  3. 遍历调用所有的SpringApplicationRunListeners的environmentPrepared()的方法,通知这些监听器SpringBoot应用的Environment已经完成初始化。
  4. 打印SpringBoot应用的banner,SpringApplication的showBanner属性为true时,如果classpath下存在banner.txt文件,则打印其内容,否则打印默认banner。
  5. 根据启动时设置的applicationContextClass和在initialize方法设置的webEnvironment,创建对应的applicationContext。
  6. 创建异常解析器,用在启动中发生异常的时候进行异常处理(包括记录日志、释放资源等)。
  7. 设置SpringBoot的Environment,注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader,通过SpringFactoriesLoader加载ApplicationContextInitializer初始化器,调用initialize方法,对创建的ApplicationContext进一步初始化。
  8. 调用所有的SpringApplicationRunListeners的contextPrepared方法,通知这些Listener当前ApplicationContext已经创建完毕。
  9. 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext
  10. 调用所有的SpringApplicationRunListener的contextLoaded方法,加载准备完毕的ApplicationContext。
  11. 调用refreshContext,注册一个关闭Spring容器的钩子ShutdownHook,当程序在停止的时候释放资源(包括:销毁Bean,关闭SpringBean的创建工厂等)
  12. 获取当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法。遍历所有的SpringApplicationRunListener的finished()方法,完成SpringBoot的启动。

springboot项目整个的启动流程相关推荐

  1. Linux上搭建SpringBoot项目部署环境和流程分享

    Linux上搭建SpringBoot项目部署环境和流程分享 背景介绍 环境搭建 1.JDK 2.Mysql 数据库 3.Redis 4.Nginx 项目部署 总结 背景介绍 最近在开发一个 Sprin ...

  2. SpringBoot 项目tomcat插件启动报错 java.lang.NoClassDefFoundError: javax/el/ELManager

    问题描述: SpringBoot项目 tomcat插件启动出现下面的问题: ERROR 2021-04-07 08:42:03,129 org.springframework.boot.SpringA ...

  3. springboot项目打war包流程

    目前,前后端分离的架构已成主流,因此使用springboot构建应用是非常快速的,项目发布到服务器上的时候,只需要打成一个jar包,然后通过命令 : java -jar jar包名称即可启动服务了: ...

  4. 2:IDEA生成springboot项目,修改启动图标和网页端口

    文章目录 1:IDEA生成springboot项目 2:修改启动图标 3:修改网页端口 1:IDEA生成springboot项目 新建 spring initializer 选择custome htt ...

  5. springboot项目创建和启动

    一.创建springboot项目 Spring Initializr: https://start.spring.io/ 通过这个网站创建springboot项目  选择基本依赖,可创建 二.启动项目 ...

  6. SpringBoot项目用tomcat启动,没有报错,控制台只输出org.apache.catalina.startup.catalina.start server startup in xxxms

    背景:最近在使用SpringBoot项目过程中,代码写好测试完,部署到服务器上启动使用外置的tomcat启动,控制台只输出org.apache.catalina.startup.catalina.st ...

  7. springboot项目jar包启动脚本

    当工具用习惯了.也就懒的去关心底层的东西了.项目部署的时候,用习惯了jenkins也就不关心运维写的脚本了.但是当工具出问题,那就要从最基础的脚本来部署项目.脚本我也不太懂,在这里只是与大家一起分享启 ...

  8. webpack项目配置与启动流程

    创建项目 npm init //然后依次填写相应信息 {"name": "test","version": "1.0.0" ...

  9. Springboot项目使用jdk17启动报错:module java.base does not “opens java.lang.invoke“

    解决方法: 启动参数增加 –add-opens java.base/java.lang.invoke=ALL-UNNAMED

最新文章

  1. ThinkPHP控制器
  2. 【Linux开发】linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet...
  3. CH - 6901 骑士放置(二分图最大独立集-二分图最大匹配+奇偶拆点)
  4. matlab中欠定方程组超定方程组_《数值天气预报》:球坐标系中的基本方程组
  5. 名图1.8智能隐藏功能_7年后再度回归 全新一代名图“大”不同_搜狐汽车
  6. win10更新后开不了机_win7在线更新window10系统
  7. python查看数据类型type_python——获取数据类型:type()、isinstance()的使用方法:...
  8. zookeeper启动后查看状态的Error contacting service. It is probably not running.错误
  9. 诺基亚手机: 诺基亚N9将在下月19日开卖 售价4400元
  10. XP经典壁纸,多少人曾爱慕你年轻时的容颜
  11. pip学习20200810
  12. html修改导航栏字体大小,CSS 制作网页导航条(下)
  13. 某宝双十一自动养猫,解放你的双手得喵币
  14. 【求助】如何在移动固态硬盘上装一个完美的移动系统
  15. Python中ArcPy实现Excel时序数据读取、反距离加权IDW插值与批量掩膜
  16. ds3617xs 华擎J3455 无线网卡m.2装千兆网卡组成链路聚合
  17. 新手上路必备的 DAX 函数(下)
  18. 博世BOSCH EDI DESADV发货通知详解
  19. html图片怎么做成链接,HTML的链接代码怎么做?HTML的图片链接怎么制作?
  20. 丢人了,我都不知道4D啊

热门文章

  1. 使用IDEA+MVN 编译Spark 1.5.2 without hive
  2. LBS移动网络基站定位
  3. git多人合作时,恢复误删文件
  4. 打造数据中心的软实力
  5. 防范网络*** 应用层防护是重点
  6. Oracle On Linux
  7. RSync服务器配置
  8. @NotBlank注解地正确使用
  9. 一个比较完善的购物车类
  10. 探寻安全管理平台(SOC)项目的关键成功因素