SpringBoot源码阅读3-启动原理

server/2024/10/9 9:38:42/
java">@SpringBootApplication
public class DistApplication {public static void main(String[] args) {// 启动入口SpringApplication.run()SpringApplication.run(DistApplication.class, args);}
}

1、服务构建

这里"服务"指的是SpringApplication对象,服务构建就是指创建SpringApplication对象。

创建对象肯定离不开构造器,SpringApplication类的构造器如下

java">// 一般都使用这个构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 1.记录传入的资源加载器this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");// 2.记录主方法类(是一个set集合)this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 3.确定Web服务类型(reactive / servlet / node)// 确定方式也很简单就是判断当前工程是否存在一些特殊的类如 org.springframework.web.reactive.DispatcherHandler 就是reactive类型// 默认是 servletthis.webApplicationType = WebApplicationType.deduceFromClasspath();// 4.加载初始化类 - 读取当前工程所有META-INF/spring.factories 文件(这个文件配置了上下问题初始化配置类、监听器类等)// BootstrapRegistryInitializer 启动注册初始化器,SpringBoot本身没有默认的"注册初始化"器所以这里是加载不到注册初始化器除非是有自定义的this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));// ApplicationContextInitializer 上下文初始化器setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// ApplicationListener 监听器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 5.通过运行栈 stackTrace 判断出 main 方法所在的类(就是启动类本身)// 后面发布启动事件要用this.mainApplicationClass = deduceMainApplicationClass();// 至此 SpringApplication 对象就构造完成了
}

以监听器为例

在这里插入图片描述

然后就是调用run()进入环境准备阶段,详见以下代码

java">public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {// 创建完 SpringApplication 对象后调用run()方法return new SpringApplication(primarySources).run(args);
}

2、环境准备

这个阶段主要就是为即将要诞生的"容器"做一些充足的准备。

java">public ConfigurableApplicationContext run(String... args) {if (this.registerShutdownHook) {SpringApplication.shutdownHook.enableShutdownHookAddition();}long startTime = System.nanoTime();// 1.创建 DefaultBootstrapContext 对象,并逐一调用initialize()启动注册初始化器的初始化方法(刚刚从 META-INF/spring.factories 文件加载到的 BootstrapRegistryInitializer)// 默认情况下这里只是创建了 DefaultBootstrapContext 对象,因为SpringBoot没有默认的注册初始化器DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 2.设置系统环境变量 java.awt.headless=true 表示缺少显示器、键盘等输入设备也可以正常启动configureHeadlessProperty();// 3.启动"服务"本身的运行监听器SpringApplicationRunListeners listeners = getRunListeners(args);// 4.发布启动事件(事件监听者为前面我们从 META-INF/spring.factories 文件加载到的7个监听器)listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);Banner printedBanner = printBanner(environment);context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);callRunners(context, applicationArguments);}catch (Throwable ex) {throw handleRunFailure(context, ex, listeners);}try {if (context.isRunning()) {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}}catch (Throwable ex) {throw handleRunFailure(context, ex, null);}return context;
}

3、容器创建

4、填充容器


http://www.ppmy.cn/server/54231.html

相关文章

flink的窗口

目录 窗口分类 1.按照驱动类型分类 1. 时间窗口&#xff08;Time window&#xff09; 2.计数窗口&#xff08;Count window&#xff09; 2.按照窗口分配数据的规则分类 窗口API分类 API调用 窗口分配器器&#xff1a; 窗口函数 增量聚合函数&#xff1a; 全窗口函数…

【MYSQL】数据类型

数据类型分类 数值类型 tinyint类型 创建一个表&#xff0c;表中变量num的数据类型为tinyint 数据越界测试&#xff1a; 在数据类型范围内都可以插入&#xff0c;越界插入会报错 创建一个表&#xff0c;表内数据类型弄成无符号的&#xff1a; 无符号的tinyint的范围为0~2…

计算机毕业设计Thinkphp/Laravel学生考勤管理系统zyoqy

管理员登录学生考勤管理系统后&#xff0c;可以对首页、个人中心、公告信息管理、年级管理、专业管理、班级管理、学生管理、教师管理、课程信息管理、学生选课管理、课程签到管理、请假申请管理、销假申请管理等功能进行相应操作&#xff0c;如图5-2所示。学生登录进入学生考勤…

半导体制造中液体污染控制:液体粒子计数器选择 北京中邦兴业

半导体制造&#xff0c;一个高度复杂且精密的工艺过程&#xff0c;涵盖多个环节与阶段&#xff0c;每一步都面临着潜在的污染风险。这种污染不仅代价高昂&#xff0c;还可能导致产量锐减和生产周期的延长。为了有效应对这些挑战&#xff0c;实时监控系统应运而生&#xff0c;成…

Redis缓存穿透

现象&#xff1a; 1、应用服务器压力变大 2、redis命中率降低 3、一直查询数据库 产生原因&#xff1b; 1、redis查询不到数据 2、出现很多非正常URL访问 解决方案&#xff1a; 1、对空值做缓存 ---如果一个查询返回的数据为空(不管是数据是否不存在)&#xff0c;我们仍然把这…

Uniapp的使用

为什么要使用uniapp uniapp 可以进行多端开发&#xff0c;uniapp 在设计的时候就拥有许多兼容性代码&#xff0c;可以兼容很多的平台 如 支付宝小程序 html页面 微信小程序等&#xff0c;注重开发效率而不是运行效率时 &#xff0c;就可以考虑一下 uniapp 当然也可以去…

产线AGV和仓储AGV到底有什么不同?

agv AGV小车虽然体积小巧&#xff0c;但这并不影响它强大的负重能力&#xff0c;它不需要人工去操作驾驶&#xff0c;能够实现无人搬运车的功能&#xff0c;而且随着AGV小车的发展&#xff0c;已经从最传统普遍的磁导航升级为惯性导引和激光导引AGV小车了&#xff0c;从需要在企…

玩转springboot之springboot配置文件

springboot配置文件 虽然springboot提供了一系列的默认配置&#xff0c;但是还是需要使用配置文件来进行一些自定义的配置 springboot中配置文件名称叫做application.properties或者application.yml 配置文件加载顺序 springboot 启动会扫描以下位置的application.properties/y…