一文教会你SpringBoot是如何启动的

9 篇文章 0 订阅
7 篇文章 2 订阅

原文链接SpringBoot启动流程分析

流程图

未命名文件 (2).png

源码剖析

运行Application.run()方法

我们在创建好一个 SpringBoot 程序之后,肯定会包含一个类:xxxApplication,我们也是通过这个类来启动我们的程序的(梦开始的地方),而这个启动类中代码如下:
image.png
可以看到这里的代码非常的简洁,一个 main方法,在该方法中调用了 SpringApplication.run() 方法,我们也可以去看一下里面的实现。
image.png
这里的run方法接收了两个参数,一个是名为 primarySource 的类,另一个是 args 参数,其中最为主要的也就是 primarySource 参数,该参数接收了我们要启动的是哪一个类,我们把滚动条拉到最上面可以看到一个构造函数:
image.png
在这个构造函数里将我们的启动类添加到了一个 LinkedHashSet中,而在它的下面有一个 webApplicationType 参数,这就是我们用来确定应用程序类型的地方。

SpringApplication构造函数

确定应用程序类型

我们去看一下 WebApplicationType.deduceFromClasspath() 方法的实现逻辑:
image.png在这里我们确定了应用程序的容器,依照上面的代码我们可以看出来一共有三种类型:Servlet(默认)Reactive(响应式编程)None

加载所有的初始化器

我们回到 SpringApplication 类的构造器中,其中有一个 this.setInitializers()方法,用来设置我们的初始化器。
image.png
而我们的初始化器是通过扫描 META-INF/spring.factories 来知道需要加载哪些初始化器的,我们也可以去点开IDEA中的SpringBoot的jar包,我们可以看到其在 META-INF 文件夹下有一个名为 spring.factories的文件。
image.png
我们点开这个文件可以发现里面是一个又一个的全限定名,而其中有一个 ApplicationContextInitializer 的全限定名,此处就是定义初始化器的地方:
image.png
我们随便点击一个进去后发现,其实现了 ApplicationContextInitializer<ConfigurableApplicationContext>中的 initialize() 方法。
那么我们也试试能不能通过他这种写法来写一个初始化器

自定义初始化器

首先我们定义一个类来实现 ApplicationContextInitializer<ConfigurableApplicationContext>,并重写一下 initialize()方法
image.png
接着我们在 resource 目录下创建一个名为 META-INF的文件夹,并在文件夹中创建一个名为 spring.factories的文件
image.png
再在其中写上我们的初始化器的全限定名即可
image.png
接着我们启动我们的应用发现我们的打印是正常的
image.png

加载所有的监听器

同样的,我们来到SpringBoot的jar包中的spring.factories 文件中,在初始化器的下方有个 ApplicationListener,我们通过名字可以猜到,这里是定义要加载的监听器的地方
image.png
我们随便点击一个进去发现,他们和初始化器一样,都实现了一个类,监听器的类为 ApplicationListener<ContextRefreshedEvent>
image.png
我们也来试试能不能写一个自定义的监听器给加载上。

自定义监听器

首先定义一个类来实现ApplicationListener 中的 onApplicationEvent()方法
image.png
再在spring.factories中来定义一下我们要加载的监听器
image.png
接着我们启动一下项目,可以看到我们的监听器成功被加载了,并且也在初始化器的后面
image.png

设置程序运行的主类

我们重新回到 SpringApplication中的构造器中,而其中的最后一行就是去设置我们程序运行的主类
image.png
而我们点入方法看一眼
image.png
我们看代码可以看到,他在寻找方法名为 main的类,并且将其返回出去,也就是说我们的程序是通过这个方法来推断我们程序的主类在哪里的。
至此,我们构造函数就执行完毕了,接下来就会进入到run方法中来运行我们的程序。

run() 方法

开启计时器

其实在原先的版本中是开启计时器,但是在新版本中使用的是通过 System.nanoTime()互减的方法来实现计时的,如下:
image.png
其最主要的作用是来计算程序启动过程中使用的时长

启用Headless模式

在run方法中我们可以看到执行了 this.configureHeadlessProperty()的方法
image.png
我们来到这个方法体中,可以看到这里是用来获取 java.awt.headless
image.png
其目的是为了让程序可以在没有显示器和鼠标的情况下也可以正常工作,用来模拟输入和输出设备

获取并开启监听器

在我们开启了 Headless 模式 后,程序获取了监听器,并将其开启了,程序如下:
image.png
那么其是如何获取监听器的呢?
image.png点进来后我们可以发现,他是通过加载 spring.factories的配置来获取到所有的监听器的,也就是刚才我们说的地方

设置应用程序参数

image.png
在这里程序是使用了默认的参数配置,如下:
image.png
此处的 args 就是我们的程序入口传入的args
image.png

准备环境变量

当我们的应用程序参数设置完成后,程序会开始准备环境变量
image.png
我们进入到 this.prepareEnvironment() 的方法体中,并在最后返回的地方打个断点
image.png
可以看到我们的环境变量均被加载进来了

忽略Bean信息

这里是将 spring.beaninfo.ignore的值设置为true,没什么好说的,原理和上面 启用Headless模式 一样
image.png

image.png

打印Banner信息

image.png
我们在这个地方来打印程序的banner,也就是我们程序运行时打印的logo
image.png
它是有一个默认值的,定义在SpringBootBanner
image.png
我们想要更改时只需要在 resource 下创建一个名为 banner.txt 的文件即可
image.png
最后我们启动就可以得到如下的输出
image.png

创建程序上下文

程序通过执行 createApplicationContext() 方法来进行创建程序的上下文对象
image.png
此处就是利用反射来创建对象

实例化异常报告器

当我们启动出错时会被捕获异常,并且执行一个名为 handleRunFailure() 的方法
image.png
我们点进去可以看到其中有一个 getExceptionReporters() 的方法
image.png
image.png
我们可以清晰的看到上面调用了getSpringFactoriesInstances()方法,此处就是在我们的 spring.factories中获取参数的方法,上面我们也提到过很多次,这里就不过多赘述了。
image.png
我们点进去发现其也是实现了一个类并重写其中的方法
image.png
那么我们也去定义一个自己的异常报告器来试试

自定义异常报告器

首先我们要先创建一个类来实现 SpringBootExceptionReporter 中的 onApplicationEvent()方法
image.png
然后在 spring.factories中定义即可
image.png
但是需要注意的是,我们的程序在执行不出错的情况下,异常报告器是不会执行的,所以我们要手动制造一个错误来使其报错。那么我们就在加载我们自定义的监听器时主动抛出一个异常。
image.png
接着我们运行程序就会得到以下结果:
image.png

准备上下文

此处程序执行了一个名为 prepareContext() 的方法
image.png
我们到方法体内可以得到如下代码:
image.png
其中比较重要的就是 postProcessApplicationContext()applyInitializers()beanFactory.registerSingleton("springApplicationArguments", applicationArguments)这三个方法,接下来我们逐一去分析

postProcessApplicationContext()

方法体如下:
image.png
其中最主要的就是这个 beanNameGenerator ,也就是 Bean名称生成器,主要的作用就是用来 创建Bean对象的名称

applyInitializers()

image.png
通过以上方法体,我们可以看到,其中有一个迭代器用于遍历,并且均执行了 initializer.initialize(context 方法,此处也就是我们的初始化方法。
那么该方法的作用就是来执行所有的初始化方法,而我们程序中的初始化器在 SpringBoot构造函数 阶段就已经加载完毕了,其实实质就是来执行我们所有的初始化器中的初始化方法。

beanFactory.registerSingleton()

image.png
此处的代码我们就更好理解了,其创建了一个 Bean工厂,并且以单例模式注册了一个东西,那么是什么呢?
没错,就是名为springApplicationArguments 的参数,但是我们英语水平不够,不知道它是什么意思怎么办?
没关系,科技使人进步,我们还有翻译软件ヾ(≧▽≦*)o
image.png
没错,是应用程序参数!我们将启动的参数以单例模式注册到我们的容器中,其目的是为了方便之后的读取使用。

刷新上下文

image.png
这里就是单纯的刷新上下文,我们之前学习的自动装配和Tomcat的启动就是在这里完成的

刷新上下文的后置处理

image.png
这里是启动后的一些处理,暂时这个方法是空的,留给用户自定义。
既然如此,那为什么不来点自定义的 afterRefresh()尝尝鲜呢o( ̄▽ ̄)ブ
首先我们要自定义一个类来继承 SpringApplication 并重写其中的 afterRefresh 方法
image.png
接着我们要去改造我们的程序入口
image.png
最后我们启动我们的程序就可以得到:
image.png

结束计时器

在老版本中我们是使用 stopWatch来完成计时器的功能的,前面也讲了,在新版本中我们是使用时间戳互减来完成我们计时的功能的
image.png

发布上下文准备就绪事件

image.png
其目的就是告诉应用程序:嘿哥们儿,我准备好了,咱们可以开始工作了。

执行自定义的run()方法

image.png
在此处我们可以看到,其加载了两个类型的run方法,一种是 ApplicationRunner,另一种是 CommandLineRunner,该方法将这两种类型的所有runnner都添加到一个 ArrayList 中,并进行排序。
在排序完成后就由迭代器来逐一执行runner的 callRunner() 方法。
那么我们也可以自定义我们的runner来使其执行。
来吧老伙计,都最后一个步骤了,跟着我一起实现一下。
image.png
只需要自定义类并实现 ApplicationRunnerCommandLineRunner并重写其中的 run()方法即可,此处为了同时演示两种方法,我就同时实现了两个类型,大家可以根据实际情况来选择。
最后我们运行程序就可以得到:
image.png
至此,我们的SpringBoot就运行完成了。
感谢观看。

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Eclipse是一个开放源代码的集成开发环境(IDE),可用于Java开发,但也可以用于其他编程语言的开发。在本文中,我将向你展示如何使用Eclipse进行Java开发。 1. 下载Eclipse 首先,你需要从Eclipse官方网站下载Eclipse IDE。下载页面上将提供几个不同的版本,包括Eclipse IDE for Java Developers、Eclipse IDE for JavaScript and Web Developers,以及Eclipse IDE for C/C++ Developers等。选择适合你的版本,然后按照安装向导进行安装。 2. 创建Java项目 一旦你安装了Eclipse,你可以启动它并创建一个新的Java项目。选择“File”->“New”->“Java Project”,然后按照向导创建一个新的Java项目。在创建项目时,你需要指定项目名称、项目类型以及JRE版本等信息。 3. 创建Java类 一旦你创建了一个Java项目,你就可以创建一个Java类。选择你的Java项目,在“src”文件夹上右键单击,然后选择“New”->“Class”。输入类名和选择要继承的类(如果有的话),然后点击“Finish”。 4. 编写Java代码 现在你已经创建了一个Java类,可以开始编写Java代码了。在Eclipse的编辑器中,你可以输入Java代码并保存它。当你保存Java文件时,Eclipse会自动编译你的代码,并在Problems视图中显示任何编译错误。 5. 运行Java程序 一旦你编写了Java代码并保存了它,你可以运行Java程序。右键单击Java文件,然后选择“Run As”->“Java Application”。如果一切顺利,你的Java程序将在控制台中输出结果。 6. 调试Java程序 如果你的Java程序出现了错误或不按预期运行,你可以使用Eclipse的调试器来调试它。在Eclipse的编辑器中,你可以设置断点并启动调试器。当程序执行到断点时,调试器会暂停程序并允许你检查变量、运行代码等。 7. 导入外部JAR包 有时,你可能需要使用外部JAR包来完成你的Java项目。在Eclipse中,你可以简单地将外部JAR包导入到你的项目中。右键单击Java项目,然后选择“Build Path”->“Configure Build Path”。在“Libraries”选项卡上,你可以添加外部JAR包。 总结 在本文中,我们介绍了如何使用Eclipse进行Java开发。我们学习了如何创建Java项目、创建Java类、编写Java代码、运行Java程序、调试Java程序以及导入外部JAR包。Eclipse具有强大的功能,可以大大提高Java开发的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bummon.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值