Springboot中ApplicationListener工作原理(源码)

一、启动参数

其中subMainClass为启动类,我的启动类是:

 二、源码

1、当springboot项目启动时,会进入run方法

 

 让我们进入第四步,看看里面都干了啥?

 接着跟进去,看看SpringFactoriesLoader.loadFactoryNames这个方法:

 其中factoryClassName:org.springframework.context.ApplicationListener,classLoader会去

META-INF/spring.factories中找ApplicationListener=XXXX这样的数据加载出来

 并把它放入result中返回,这其中有随便拿一个类出来打上断点,看看什么时候调用,比如:

 ClearCachesApplicationListener这个类,断点如下:

 从第六步中的方法:SpringFactoriesLoader.loadFactoryNames出来后,接着往下走,进入方法:

createSpringFactoriesInstances,

 其中,

type:interface org.springframework.context.ApplicationListener

parameterTypes:[]

classLoader:sun.misc.Launcher$AppClassLoader@14dad5dc

args:[]

names:从META-INF/spring.factories中获取的集合

这个方法的意思是,将所有names调用无参构造反射进行实例化,如下图所示:

 这个方法执行完成之后,就一直往上返回,返回到第四步,执行setListeners方法,

 

 就是将这个实例化的集合添加到到SpringApplication类的listeners属性中:

此时,第二步中的new SpringApplication(sources)已经走完,接着看看run(args)方法,

 跟着2-1往里面走:

 让我们先看2-2中的方法:getSpringFactoriesInstances,其中:

this:org.springframework.boot.SpringApplication@10feca44

args:[config.server=192.168.2.155:2181, config.auth=123456, config.namespace=dev, config.appid=ms.roster.weizhi] 就是我的启动入参

让我们接着看2-3中的方法做了些什么,其中SpringFactoriesLoader.loadFactoryNames是不是很眼熟,就是从META-INF/spring.factories获取了key为org.springframework.boot.SpringApplicationRunListener的数据集:

 然后,调用createSpringFactoriesInstances方法进行反射实例化,调用的有参构造:

 其实就是调用类EventPublishingRunListener中的有参构造:

 接着我们来看看这个构造参数,实例化了类:SimpleApplicationEventMulticaster,遍历application.getListeners(),其实就是 :

 这步中的listeners,拿到的就是:

这里面的实例对象,让我们接着来看,将遍历后的listener放入initialMulticaster中:

this.initialMulticaster.addApplicationListener(listener);

 其实是将listener最终放在了ListenerRetriever的applicationListeners中,其中SimpleApplicationEventMulticaster是继承AbstractApplicationEventMulticaster类

 也就是说,最终将所有的ApplicationListener都放入了类ListenerRetriever的属性applicationListeners中,此处也是重点。

那么接着就会从2-3返回,结果如下:

 这个就是2-2中getSpringFactoriesInstances执行完的结果,接着执行方法:new SpringApplicationRunListeners方法:将结果集装入org.springframework.boot.SpringApplicationRunListeners.listeners中,那么就是:

SpringApplicationRunListeners装有SpringApplicationRunListener实现类的结果集,SpringApplicationRunListener实现类中装有ApplicationListener实现类的结果集,这样一层一层包装也就是说:

 那么,执行完之后一层一层往上返回,到达2-1中,接着往下执行方法:listeners.starting();

 跟进去看看:

 将listeners中的SpringApplicationRunListener拿出来遍历,接着跟进去:listener.starting(),就是EventPublishingRunListener中的方法:

 其中:this.application, this.args就是前面2-4中传入的SpringApplication实例和启动入参,封装进类ApplicationStartedEvent中,并将ApplicationStartedEvent传入方法:

this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));

 

 让我们接着看2-10中的方法:getApplicationListeners

其实2-11中的source就是 this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));方法中的this.application

跟着2-12这个重要的方法往里面走:

2-13的这个取值是不是很熟悉,就是从2-6中的取得集合,然后往上返回,返回到2-10中,进行遍历,执行方法:invokeListener

 说白了,就是循环执行每一个ApplicationListener实现类的方法:onApplicationEvent,那么让我们最终看看上面打了断点的类:ClearCachesApplicationListener是不是就会被执行了:

 最终完美被拿捏,哈哈哈哈哈~~~~

但是!!!!!!

经过我仔细的调试,发现ClearCachesApplicationListener中的方法并不是在listeners.starting()中执行的,难道是哪儿出了问题,那就让我们仅需深入的看看

 让我们重新进到2-12里面:

发现返回值竟然只有5个,如下:

 其中并没有ClearCachesApplicationListener,不要着急,我们在往上找找,进入方法:retrieveApplicationListeners,也就是2-13,发现ClearCachesApplicationListener还存在,接着往下走,以为最终这个方法返回的是allListeners,结果这儿allListeners中就已经只剩5个实例了,那么问题一定是出在这儿,让我们仔细瞅瞅:

 发现这个方法:supportsEvent很可疑,那么我们就来看看这个方法到底做了啥吧?

 外层for循环到了类ClearCachesApplicationListener,我们发现,listener instanceof GenericApplicationListener=false,那么就要走new GenericApplicationListenerAdapter(listener)这段逻辑,最终我们发现,它将EventType进行了解析:

 然后接着往下走,我们就发现:

那么,就没有必要往下看了,因为 ClearCachesApplicationListener类中的EventType为ContextRefreshedEvent,而非ApplicationStartedEvent,所以直接返回false,那么在2-17中自然就不会被add到allListeners集合中,所以,小伙伴们,这就能解释清楚了,好,一切搞定,收工!!!!!!!!!

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值