04、SpringBoot 源码分析 - SpringApplication启动流程四

SpringBoot 源码分析 - SpringApplication启动流程四

  • 初始化基本流程
  • SimpleApplicationEventMulticaster的multicastEvent广播事件
    • resolveDefaultEventType获取ResolvableType实例
      • ResolvableType的forInstance创建ResolvableType实例
    • 开始广播
      • AbstractApplicationEventMulticaster的getApplicationListeners获取所有支持该事件的监听器
      • DefaultListenerRetriever
        • getApplicationListeners直接获取监听器集合
      • AbstractApplicationEventMulticaster的retrieveApplicationListeners

初始化基本流程

在这里插入图片描述

SimpleApplicationEventMulticaster的multicastEvent广播事件

其实这个就是观察者模式,发布订阅模式,或者说事件驱动模式,如果看过netty就知道他里面的处理器的方法就是事件驱动模式,这里会先进行事件类型解析,解析成ResolvableType类型。
org.springframework.context.event.SimpleApplicationEventMulticaster

@Overridepublic void multicastEvent(ApplicationEvent event) {multicastEvent(event, resolveDefaultEventType(event));}

resolveDefaultEventType获取ResolvableType实例

	private ResolvableType resolveDefaultEventType(ApplicationEvent event) {return ResolvableType.forInstance(event);}

ResolvableType的forInstance创建ResolvableType实例

如果是ResolvableTypeProvider类型就会获取类型实例返回,否则会创建一个ResolvableType 对象,将事件类型封装进去。

	public static ResolvableType forInstance(@Nullable Object instance) {if (instance instanceof ResolvableTypeProvider) {ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType();if (type != null) {return type;}}return (instance != null ? forClass(instance.getClass()) : NONE);}public static ResolvableType forClass(@Nullable Class<?> clazz) {return new ResolvableType(clazz);//创建一个,把clazz封装进去}

开始广播

获取所有监听器,如果没有执行器就直接调用,有的话会开线程调用,最终都是 invokeListener

	@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}}

AbstractApplicationEventMulticaster的getApplicationListeners获取所有支持该事件的监听器

现在有个启动事件,但是不一定所有监听器都要支持该事件,如果不支持表示对此事件不关心,那就不需要通知给他了,所以这里就是为了找出支持该事件的监听器集合,找出来之后还会给事件和监听器集合做映射,放入缓存中。

protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {//获取事件源,就是事件是谁触发的Object source = event.getSource();Class<?> sourceType = (source != null ? source.getClass() : null);//事件源类型//封装事件类型和事件源类型ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);// 定义一个检索器CachedListenerRetriever newRetriever = null;// 从缓存中获取CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey); //获取监听器检索其if (existingRetriever == null) {// Caching a new ListenerRetriever if possibleif (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {newRetriever = new CachedListenerRetriever();existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);if (existingRetriever != null) {newRetriever = null;  // no need to populate it in retrieveApplicationListeners}}}if (existingRetriever != null) {//获取支持该事件的监听器集合,并放入retriever中Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();if (result != null) {return result;}}//不用缓存的情况,每次都取一遍return retrieveApplicationListeners(eventType, sourceType, newRetriever);}

DefaultListenerRetriever

这个其实就是存监听器的,但是只是对某些事件支持的监听器集合,可以是实例,也可以是 bean 的名字。

private class DefaultListenerRetriever {public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();public final Set<String> applicationListenerBeans = new LinkedHashSet<>();}
getApplicationListeners直接获取监听器集合

直接获取就是将bean名字的集合里的bean都实例化,然后跟监听器合并,去重,最后返回

public Collection<ApplicationListener<?>> getApplicationListeners() {List<ApplicationListener<?>> allListeners = new ArrayList<>(this.applicationListeners.size() + this.applicationListenerBeans.size());allListeners.addAll(this.applicationListeners);if (!this.applicationListenerBeans.isEmpty()) {BeanFactory beanFactory = getBeanFactory();for (String listenerBeanName : this.applicationListenerBeans) {try {ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class);if (!allListeners.contains(listener)) {allListeners.add(listener);}}catch (NoSuchBeanDefinitionException ex) {// Singleton listener instance (without backing bean definition) disappeared -// probably in the middle of the destruction phase}}}AnnotationAwareOrderComparator.sort(allListeners);return allListeners;}

AbstractApplicationEventMulticaster的retrieveApplicationListeners

这个就是根据监听器是否支持该事件,进行监听器的筛选,最后把支持的监听器集合返回。其实还会涉及到bean名字的集合,支持该事件的会直接获取,然后放进不同的集合里,最后都会讲所有支持的监听器全部返回。这里会把监听器集合也放在ListenerRetriever里,以便于做事件类型和监听器集合的映射缓存。

private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {List<ApplicationListener<?>> allListeners = new ArrayList<>();Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);Set<ApplicationListener<?>> listeners;Set<String> listenerBeans;synchronized (this.defaultRetriever) {//获取SimpleApplicationEventMulticaster添加监听器的时候就加入进去的监听器集合listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}// Add programmatically registered listeners, including ones coming// from ApplicationListenerDetector (singleton beans and inner beans).for (ApplicationListener<?> listener : listeners) {//遍历所有的监听器,看监听器是否支持该事件if (supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {filteredListeners.add(listener);//支持就添加进去}allListeners.add(listener);//也添加到allListeners里}}// Add listeners by bean name, potentially overlapping with programmatically// registered listeners above - but here potentially with additional metadata.if (!listenerBeans.isEmpty()) {//如果有监听的bean的话,也要加进去ConfigurableBeanFactory beanFactory = getBeanFactory();for (String listenerBeanName : listenerBeans) {try {if (supportsEvent(beanFactory, listenerBeanName, eventType)) {//支持该事件的直接获取ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class);if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {if (beanFactory.isSingleton(listenerBeanName)) {filteredListeners.add(listener);}else {filteredListenerBeans.add(listenerBeanName);}}allListeners.add(listener);}}else {//不支持就删除// Remove non-matching listeners that originally came from// ApplicationListenerDetector, possibly ruled out by additional// BeanDefinition metadata (e.g. factory method generics) above.Object listener = beanFactory.getSingleton(listenerBeanName);if (retriever != null) {filteredListeners.remove(listener);}allListeners.remove(listener);}}catch (NoSuchBeanDefinitionException ex) {// Singleton listener instance (without backing bean definition) disappeared -// probably in the middle of the destruction phase}}}AnnotationAwareOrderComparator.sort(allListeners);if (retriever != null) {if (filteredListenerBeans.isEmpty()) {retriever.applicationListeners = new LinkedHashSet<>(allListeners);retriever.applicationListenerBeans = filteredListenerBeans;}else {retriever.applicationListeners = filteredListeners;retriever.applicationListenerBeans = filteredListenerBeans;}}return allListeners;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/691978.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在bud里弄3d模型?---模大狮模型网

随着数字化设计的不断发展&#xff0c;越来越多的设计软件提供了对3D模型的支持&#xff0c;为设计师们带来了更广阔的创作空间。Bud作为一款功能强大的设计工具&#xff0c;也提供了添加和编辑3D模型的功能&#xff0c;让用户能够更加灵活地进行设计创作。本文将为您详细介绍如…

数据结构之排序(上)

片头 嗨&#xff0c;小伙伴们&#xff0c;大家好&#xff01;我们今天来学习数据结构之排序&#xff08;上&#xff09;&#xff0c;今天我们先讲一讲3个排序&#xff0c;分别是直接插入排序、冒泡排序以及希尔排序。 1. 排序的概念及其应用 1.1 排序的概念 排序&#xff1a…

FPGA第1篇,FPGA现场可编程门阵列,从0开始掌握可编程硬件开发(FPGA入门指南)

简介&#xff1a;FPGA全称Field-Programmable Gate Array&#xff0c;是一种可编程逻辑器件&#xff0c;它通过可编程的逻辑单元和可编程的连接网络实现了灵活的硬件实现。与固定功能的集成电路&#xff08;ASIC&#xff09;相比&#xff0c;FPGA具有更高的灵活性和可重新配置性…

Tomcat端口占用解决方案

Windows操作系统 出现这种情况&#xff1a; Error was Port already in use :40001&#xff1b;nested exception is :java.net.BindException: Address already in use : JVM_Bind; 步骤1&#xff1a;按下winR键&#xff0c;输入cmd 步骤2&#xff1a;输入以下命令 netstat …

ipa 分区算法分析,图解

参考 Room Segmentation: Survey, Implementation, and Analysis. 分区算法调查&#xff0c;实现以及评估对比 相关论文 分区算法 New Brooms Sweep Clean - An Autonomous Robotic Cleaning Assistant for Professional Office Cleaning 形态分割 Interactive SLAM using …

体验GM CHM Reader Pro,享受高效阅读

还在为CHM文档的阅读而烦恼吗&#xff1f;试试GM CHM Reader Pro for Mac吧&#xff01;它拥有强大的功能和出色的性能&#xff0c;能够让你轻松打开和阅读CHM文件&#xff0c;享受高效、舒适的阅读体验。无论是学习、工作还是娱乐&#xff0c;GM CHM Reader Pro都能成为你的得…

Lab4: traps

RISC-V assembly Which registers contain arguments to functions? For example, which register holds 13 in mains call to printf? 根据RISC-V函数调用规范&#xff0c;函数的前8个参数使用a0-a7寄存器传递。 当main函数调用printf函数时&#xff0c;a2寄存器保存13 …

力扣:48. 旋转图像(Java)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使…

在Excel中转置行和列的几种方法,总有一种适合你

序言 如果你开始以垂直排列(列)的方式输入数据,然后决定以水平排列(行)的方式更好,Excel将为你提供帮助。我们将研究在Excel中转换数据的三种方法。 静态方法 在这种方法中,你可以快速轻松地将数据从列转换到行(反之亦然),但它有一个关键的缺点:它不是动态的。例…

iZotope RX 11 for Mac 激活版:让您的音频焕发生机!

在追求音频完美的道路上&#xff0c;iZotope RX 11 for Mac是您的得力助手。它凭借先进的音频修复技术和丰富的音频增强工具&#xff0c;让您的音频作品焕发出前所未有的生机与活力。无论您是专业的音频工程师&#xff0c;还是业余的音乐爱好者&#xff0c;都能在这款工具中找到…

Python从0到POC编写-魔法方法

name __name__ 是系统定义的内部函数&#xff0c; 它的作用是识别模块。 通常我们看到这样一句话&#xff1a; if __name__ __main____name__ 的值有两种情况&#xff0c;那么挨个来说下。 如果模块是被直接执行的 &#xff0c;那么 __name__ 的值 为 __main__ 例如&…

247 基于matlab的梁的振型仿真

基于matlab的梁的振型仿真。利用有限元理论&#xff0c;求二维梁的固有频率和振型。短边固定&#xff0c;给定长度、横截面积&#xff0c;弹性模量及材料密度已知。并对比理论计算结果进行分析。各参数自己设定。程序已调通&#xff0c;可直接运行。 247 梁的振型仿真 固有频率…