SpringBoot事件与监听机制

本文通过SpringBoot项目的运行,来探讨SpringBoot事件与监听机制。springboot版本:2.0.2.RELEASE

SpringBoot事件与监听机制

发现SpringBoot事件

通常我们启动应用就使用这么一条命令SpringApplication.run(XXXX.class,args);然后我们的项目就启动了。我们跟踪进去,就会来到下图的run方法。
在这里插入图片描述
从图中代码可知:

  1. 构造SpringApplication对象
  2. 调用该对象的run方法
  3. 该对象的run方法返回了实现ConfigurableApplicationContext接口的对象

与我们主题相关的内容在run方法里。
在这里插入图片描述
在方法里我们可以看到这条命令:
SpringApplicationRunListeners listeners = getRunListeners(args);然后后续的代码里与listeners相关的命令有这些:
listeners.starting();
prepareEnvironment(listeners, applicationArguments);
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
listeners.started(context);
listeners.running(context);
而随着这些命令的执行,就会发布不同的事件。后面我们将看看各条命令具体做了些什么事情,不过现在首先看看listeners是如何被实例化的。

SpringApplicationRunListeners的构造

在这里插入图片描述
从代码我们可以知道,它构造了SpringApplicationRunListeners对象。调用该对象的构造函数时传进了两个参数。我们先看SpringApplicationRunListeners构造函数的内容:
在这里插入图片描述
其实就是传入了日志器以及SpringApplicationRunListener集合,并将这两参数作为自己的属性。请注意,一个是SpringApplicationRunListeners,一个是SpringApplicationRunListener。从字面上看,前者是后者的复数形式。

SpringApplicationRunListener的构造

我们回到getRunListeners方法里,在调用SpringApplicationRunListeners构造函数时,以getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)命令的返回值作为第二个参数值。另外,getSpringFactoriesInstances方法会调用SpringFactoriesLoader.loadFactoryNames方法,该方法从类路径META-INF/spring.factories文件里找到以SpringApplicationRunListener的完整类名为key的属性值。属性值比较简单,就中只有一个类名org.springframework.boot.context.event.EventPublishingRunListener,然后通过反射机制,调用该类的构造函数得到该对象EventPublishingRunListener。
从当前版本的springboot来看,只有spring-boot-2.0.2.RELEASE.jar的spring.factories文件里才有定义。所以EventPublishingRunListener就是唯一的SpringApplicationRunListener了。
我们再回头看各自的定义。SpringApplicationRunListeners是一个类,而SpringApplicationRunListener是一个接口,后者声明的方法前者都有,而且前者方法基本上是轮循调用SpringApplicationRunListener集里的各个元素对应的方法,所以这种形式象极了组合模式。更进一步,我们完全可以象EventPublishingRunListener的声明方式那样,在自已工程里的/META-INF/spring.properties内也配置自定义的SpringApplicationRunListener实现类,这样就可以在SpringApplicationRunListeners的不同方法被调用时,发布自定义的事件了。

事件的发布

因为EventPublishingRunListener是唯一的SpringApplicationRunListener接口的实现类,所以它实现了接口声明的方法。从EventPublishingRunListener的代码不难看出每个方法都会发布不同的事件。现归纳如下:

方法 事件
starting ApplicationStartingEvent
environmentPrepared ApplicationEnvironmentPreparedEvent
contextPrepared
contextLoaded ApplicationPreparedEvent
started ApplicationStartedEvent
running ApplicationReadyEvent
failed ApplicationFailedEvent
事件的类图

在这里插入图片描述若仔细看的话会发现,Springboot的事件都是扩展于spring的ApplicationEvent。

监听者

现在已经知道springboot有什么事件和事件发布者是谁了,那么监听者又是从何而来?
我们暂时回到较早前的代码片段:
在这里插入图片描述
前文描述的事件发布平台、事件发布者都是在构造了SpringApplication对象后调用它的run方法里出现的。而监听者是在构造SpringApplication对象的过程中出现的。
在这里插入图片描述那么发布事件发布者与监听者是怎么开成关联呢?其实就在构造EventPublishingRunListener的时候就产生关联关系了:
在这里插入图片描述但监听者不是直接成为EventPublishingRunListener的属性,而是被加到它的initialMulticaster属性里面去了。
因为构造EventPublishingRunListener的时侯,是在 return new SpringApplication(primarySources).run(args); 这条命令的run阶段,而listener是在构造SpringApplication阶段产生,所以构造EventPublishingRunListener时能够获取到listener。

事件发布者

经过前文的铺垫,我们相当于已经知道事件的发布者是谁了。以发布ApplicationStartingEvent为例,发布事件的调用链如下:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值