当前位置: 首页 > news >正文

十一、Spring源码学习之registerListeners方法

registerListeners()方法

protected void registerListeners() {// Register statically specified listeners first.//获取容器中事件监听并存放到多播器中 applicationListenersfor (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);//从容器中获取事件监听的beanName 存放到多播器中for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...//在早期添加到容器的事件 通过多播器执行事件Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}

SimpleApplicationEventMulticaster#multicastEvent()方法

public 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);}}}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {doInvokeListener(listener, event);}}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {//调用监听器的onApplicationEvent方法执行listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg = ex.getMessage();if (msg == null || matchesClassCastMessage(msg, event.getClass())) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// -> let's suppress the exception and just log a debug message.Log logger = LogFactory.getLog(getClass());if (logger.isTraceEnabled()) {logger.trace("Non-matching event type for listener: " + listener, ex);}}else {throw ex;}}}

AbstractApplicationEventMulticaster#getApplicationListeners()方法

protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {Object source = event.getSource();Class<?> sourceType = (source != null ? source.getClass() : null);//根据事件sourceType和事件Type 构建缓存keyListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);// Quick check for existing entry on ConcurrentHashMap...//根据key从retrieverCache缓存中获取ListenerRetriever//获取监听该事件的所有监听器ListenerRetriever retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {//如果缓存中存在,则返回所有的监听器return retriever.getApplicationListeners();}if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {// Fully synchronized building and caching of a ListenerRetrieversynchronized (this.retrievalMutex) {//再次从缓存中获取,防止重复加载retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {return retriever.getApplicationListeners();}retriever = new ListenerRetriever(true);//根据事件Type和目标sourceType 及缓存 获取符合条件的监听器,并且将监听器放到缓存中Collection<ApplicationListener<?>> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);this.retrieverCache.put(cacheKey, retriever);return listeners;}}else {// No ListenerRetriever caching -> no synchronization necessaryreturn retrieveApplicationListeners(eventType, sourceType, null);}}

AbstractApplicationEventMulticaster#retrieveApplicationListeners()方法

private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {List<ApplicationListener<?>> allListeners = new ArrayList<>();Set<ApplicationListener<?>> listeners;Set<String> listenerBeans;synchronized (this.retrievalMutex) {//将已经存在的所有监听器和beanName 存放到临时集合中listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}//遍历所有的监听器for (ApplicationListener<?> listener : listeners) {//判断当前监听器是否监听eventType事件if (supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {//是 则放入缓存retriever.applicationListeners.add(listener);}allListeners.add(listener);}}if (!listenerBeans.isEmpty()) {BeanFactory beanFactory = getBeanFactory();for (String listenerBeanName : listenerBeans) {try {//遍历所有的监听器beanNameClass<?> listenerType = beanFactory.getType(listenerBeanName);//判断监听器是否监听了该事件if (listenerType == null || supportsEvent(listenerType, eventType)) {//拿到该监听器ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class);//如果 allListeners中不存在 && 该监听器确实监听该事件if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {//并且该事件是单例beanif (beanFactory.isSingleton(listenerBeanName)) {//则放入缓存中retriever.applicationListeners.add(listener);}else {retriever.applicationListenerBeans.add(listenerBeanName);}}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);//如果缓存对象不是null && applicationListenerBeans是空的if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {retriever.applicationListeners.clear();//则将该所有符合条件的监听器放入缓存中retriever.applicationListeners.addAll(allListeners);}return allListeners;}
//当前事件是否被当前监听器监听
protected boolean supportsEvent(Class<?> listenerType, ResolvableType eventType) {if (GenericApplicationListener.class.isAssignableFrom(listenerType) ||SmartApplicationListener.class.isAssignableFrom(listenerType)) {return true;}ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));}
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));}

相关文章:

十一、Spring源码学习之registerListeners方法

registerListeners()方法 protected void registerListeners() {// Register statically specified listeners first.//获取容器中事件监听并存放到多播器中 applicationListenersfor (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationE…...

Oracle 控制文件详解

1、控制文件存储的数据信息 1&#xff09;数据库名称和数据库唯一标识符&#xff08;DBID) 2&#xff09;创建数据库的时间戳 3&#xff09;有关数据文件、联机重做日志文件、归档重做日志文件的信息 4&#xff09;表空间信息 5&#xff09;检查点信息 6&#xff09;日志序列号…...

活体成像应用染料CY3.5-NHS星戈瑞

活体成像是一种生物医学研究的重要工具&#xff0c;它能够实时、无创地观察生物体内细胞和分子的动态变化。染料CY3.5-NHS&#xff0c;作为一种常用的活体成像染料&#xff0c;在许多生物医学研究中发挥着关键作用。本文将详细介绍染料CY3.5-NHS的特点、应用以及优势&#xff0…...

【优选算法】专题1 -- 双指针 -- 复写0

前言&#xff1a; 补充一下前文没有写到的双指针入门知识&#xff1a;专题1 -- 双指针 -- 移动零 目录 基础入门知识&#xff1a; 1. 复写零&#xff08;easy&#xff09; 1. 题⽬链接&#xff1a;1089.复习0 - 力扣&#xff08;LeetCode&#xff09; 2. 题⽬描述&#xff…...

GESP Python编程三级认证真题 2024年3月

Python 三级 2024 年 03 月 1 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 小杨的父母最近刚刚给他买了一块华为手表&#xff0c;他说手表上跑的是鸿蒙&#xff0c;这个鸿蒙是&#xff1f;&#xff08; &#xff09; A. 小程序 B. 计时器 C. 操作系统…...

前端理论总结(css3)——link/import区别 // 伪类/伪元素

伪类/伪元素 1&#xff1a; 伪类使用1个冒号&#xff0c;常见的有&#xff1a;:hover&#xff0c;:link&#xff0c;:active&#xff0c;:target&#xff0c;:not()&#xff0c;:focus等 伪元素使用 2 个冒号&#xff0c;常见的有&#xff1a;::before&…...

ntp服务器搭建

1、手动修改时区 CST可以为如下4个不同的时区的缩写: 美国中部时间:Central Standard Time (USA) UT-6:00 澳大利亚中部时间:Central Standard Time (Australia) UT+9:30 中国标准时间:China Standard Time UT+8:00 古巴标准时间:Cuba Standard Time UT-4:00小结: UTC:…...

对象的内存布局

在Java虚拟机&#xff08;HotSpot&#xff09;中&#xff0c;对象在 Java 内存中的 存储布局 可分为三块&#xff1a; 对象头 存储区域实例数据 存储区域对齐填充 存储区域 对象头区域&#xff1a; 存储对象自身的运行时数据&#xff0c;如&#xff1a;哈希码、GC分代年龄、锁状…...

docker centos7离线安装ElasticSearch单机版

目录 1.下载ES并解压2.新建elasticsearch用户3.修改ES配置文件4.启动ES服务5.设置开机启动 本文以 elasticsearch-7.8.1为例。 1.下载ES并解压 cd /root/install wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.8.1-linux-x86_64.tar.gz tar -z…...

【计算机网络】IP 协议

网络层IP协议 一、认识 IP 地址二、IP 协议报头格式三、网段划分1. 初识子网划分2. 理解子网划分3. 子网掩码4. 特殊的 IP 地址5. IP 地址的数量限制6. 私有 IP 地址和公网 IP 地址7. 理解全球网络&#xff08;1&#xff09;理解公网&#xff08;2&#xff09;理解私网&#xf…...

刷题DAY38 | LeetCode 509-斐波那契数 70-爬楼梯 746-使用最小花费爬楼梯

509 斐波那契数&#xff08;easy&#xff09; 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1)…...

蓝桥杯-卡片换位

solution 有一个测试点没有空格&#xff0c;要特别处理&#xff0c;否则会有一个测试点运行错误&#xff01; 还有输入数据的规模在变&#xff0c;小心顺手敲错了边界条件 #include<iostream> #include<string> #include<queue> #include<map> #incl…...

Unity 布局控制器Content Size Fitter

Content Size Fitter是Unity中的一种布局控制器组件&#xff0c;用于根据其内容的大小来调整包含它的UI元素的大小。换句话来说就是&#xff0c;Content Size Fitter可以根据UI元素内部内容的大小&#xff0c;自动调整UI元素的大小&#xff0c;以确保内容能够正确显示。 如下图…...

Python的面向对象、封装、继承、多态相关的定义,用法,意义

面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它使用对象的概念来模拟现实世界的实体&#xff0c;并通过类&#xff08;Class&#xff09;来创建这些实体的蓝图。OOP的核心概念包括封装、继承和多态。 Python中的面向对象编程 在Python中&#xff0c;一…...

Elasticsearch 向量搜索

目标记录 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻","你好&#xff0c;我的病人","世界真美丽"] 搜索词 爱人 预期返回 ["你好&#xff0c;我的爱人","你好&#xff0c;我的爱妻"] 示例代码…...

2024蓝桥杯每日一题(背包)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;货币系统 试题二&#xff1a;01背包问题 试题三&#xff1a;完全背包问题 试题一&#xff1a;货币系统 【题目描述】 给定 V 种货币&#xff08;单位&#xff1a;元&#xff09;&#xff0c;每…...

Redis桌面客户端

3.4.Redis桌面客户端 安装完成Redis&#xff0c;我们就可以操作Redis&#xff0c;实现数据的CRUD了。这需要用到Redis客户端&#xff0c;包括&#xff1a; 命令行客户端图形化桌面客户端编程客户端 3.4.1.Redis命令行客户端 Redis安装完成后就自带了命令行客户端&#xff1…...

让Unity的协程变得简单

作者简介: 高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢…...

2.9 Python缩进规则(包含快捷键)

Python缩进规则&#xff08;包含快捷键&#xff09; 和其它程序设计语言&#xff08;如 Java、C 语言&#xff09;采用大括号“{}”分隔代码块不同&#xff0c;Python采用代码缩进和冒号&#xff08; : &#xff09;来区分代码块之间的层次。 在 Python 中&#xff0c;对于类…...

任务记录.

播放器端的解码同步问题 miracast的投屏问题&#xff0c;进行修改的问题。 播放器ffplay命令没有声音的修改问题。 任务&#xff1a;如何将断开连接后在连接发送的数据&#xff0c;两秒后再去显示。 猜测&#xff1a; 一直在监听。断开后要求2秒后的数据再显示。那么也就是认为…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...