Spring boot源码二:启动类源码

SpringApplication.run(SpringBootTestApplication.class, args);通过这样一键启动spring boot,对这段代码研究:

run方法中首先会实例化一个SpringApplication,其构造函数如下:

point1:

这里判断当前的应用类型,通过WebApplicationType.deduceFromClasspath()方法,原理是通过判断有没有加载到几个特定的类,这里我们如果是Servlet应用的话,其判断结果就是Servlet,最终赋值个webApplicationType变量。

point2:

getSpringFactoriesInstances方法能从spring.factories文件中实例化指定的类(底层用的是反射),这里赋值了两种类型的对象:

1.ApplicationContextInitializer

属于初始化回调类,下面boot上下文实例化完成之后,会回调这些类

2.ApplicationListener

负责接收事件的事件监听器,就是Spring Event机制中的那个ApplicationListener

 

SpringApplication对象实例化完成之后,会调用该实例的run方法:

getRunListeners方法也是通过getSpringFactoriesInstances方法去实例化SpringApplicationRunListener类型的对象,这里的SpringApplicationRunListener是一个接口,其唯一实现就是EventPublishingRunListener,spring.factories中也确实有该定义:

那么这个EventPublishingRunListener是用来干什么的?其名字虽然是一个Listener,但不是一个单纯的Listener。我们看下他的构造方法:

首先new了一个SimpleApplicationEventMulticaster,这个对象之前分析spring的事件机制时说过是一个事件广播器对象。

然后会将当前的SpringApplication作为构造函数参数传递进去,这一步其实很关键,因为我们有了事件广播器之后,就要有事件监听器,而这些事件监听器已经在前面通过getSpringFactoriesInstances方法加入到SpringApplication对象中了,所以这一步相当于EventPublishingRunListener得到了SpringApplication下的所有ApplicationListener,最后交给了SimpleApplicationEventMulticaster这个事件广播器。

我们来看下EventPublishingRunListener对象的几个方法:

框出来的都是其发布事件的方法,以contextLoaded方法为例,最终发布的是一个ApplicationPreparedEvent事件:

所以总结下:

EventPublishingRunListener内部维护了一个事件广播器SimpleApplicationEventMulticaster以及所有事件监听器ApplicationListener,主要就是用来发布广播事件(通过SimpleApplicationEventMulticaster这个实例),当spring boot广播一个事件时,会循环所有的ApplicationListener,上面图中划箭头的地方都是spring boot处理完某些步骤之后,会广播各种事件出来。

这里须要说明的是EventPublishingRunListener内部维护的SimpleApplicationEventMulticaster是直接new出来的,和最终spring容器中的那个SimpleApplicationEventMulticaster并不是同一个。事实上,spring boot仅仅只是通过EventPublishingRunListener对象在容器启动的时候发布和接收一些事件罢了,和在容器运行过程中使用的事件发布监听机制用的并不是同一个SimpleApplicationEventMulticaster对象!

换句话说Spring Boot的事件发布和监听机制其实有两套,一套发生在容器启动过程中,一套发生在容器启动之后。

这里有两个地方可以印证:

1.EventPublishingRunListener对象是一个局部变量:

2.Spring Boot官方文档的描述:

这里面有两个信息点:

1) 假如我们须要监听类似ApplicationStartingEvent事件的,因为这个事件的广播是在ApplicationContext创建之前的(对应源码中就是说这个时候的事件广播器只是EventPublishingRunListener中new出来的一个广播器,而非spring容器初始化之后的那个作为一个单例bean的广播器),所以我们不能通过@Bean的形式注入事件监听器。

2) 如果须要自定义一个监听器监听ApplicationStartingEvent事件的话,可以使用SpringApplication.addListeners(…​) 方法或者 SpringApplicationBuilder.listeners(…​) 方法,也可以在自己的META-INF/spring.factories下面声明这个监听器。

 

上面一直说这里的事件发布是在ApplicationContext对象创建之前的,那么之后就要创建ApplicationContext对象了:

首先是createApplicationContext()方法:

通过当前的应用类型(就是之前赋值的webApplicationType)运用反射实例化一个ApplicationContext对象出来,这里如果是Servlet的话,实例化出来的是一个AnnotationConfigServletWebServerApplicationContext对象。

prepareContext方法和refreshContext方法:

这两步其实就是对应spring中AbstractApplicationContext#refresh方法,做一些容器初始化工作,只是实现方式不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值