【Spring

2023-11-19

上篇 Spring 事件监听概述 对 Spring 事件监听的机制有了个基本的了解。
本篇来详细的解读下Spring 的 事件监听机制

ApplicationEvent


  ApplicationEvent最重要的子类是ApplicationContextEvent抽象类,ApplicationContextEvent是spring容器Context生命周期事件的基类。

ApplicationContextEvent的有四个子类,如下:

  • ContextRefreshedEvent:当spring容器context刷新时触发
  • ContextStartedEvent:当spring容器context启动后触发
  • ContextStoppedEvent:当spring容器context停止时触发
  • ContextClosedEvent:当spring容器context关闭时触发,容器被关闭时,其管理的所有单例Bean都被销毁。

  以上四个事件就是spring容器生命周期的四个事件,当每个事件触发时,相关的监听器就会监听到相应事件,然后触发onApplicationEvent方法,此时就可以做一些容器,同时这些容器事件跟spring的后置处理器一样,留给用户扩展自定义逻辑,作为暴露的扩展点。

ApplicationEvent 重要的子类关系图如下:
在这里插入图片描述

示例:

public class BlockedListEvent extends ApplicationEvent {

	private final String address;
	private final String content;

	public BlockedListEvent(Object source, String address, String content) {
		super(source);
		this.address = address;
		this.content = content;
	}

	// accessor and other methods...
}

ApplicationListener


  ApplicationListener (继承自JDK的EventListener,JDK要求所有的监听器继承它。)是所有事件监听器的接口,事件监听器监听某个事件必须要实现该接口。
  ApplicationListener 通常使用自定义事件的类型(在前面的示例中为BlockedListEvent)进行参数化。这意味着 onApplicationEvent() 方法可以保持类型安全,避免任何向下转型的需要。您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件侦听器同步接收事件。这意味着publishEvent()方法将阻塞,直到所有侦听器完成对事件的处理。这种同步单线程方法的优点之一是,当侦听器接收事件时,如果事务上下文可用,它会在发布者的事务上下文内进行操作。若想提供顺序触发监听器的语义,则可以使用另一个接口SmartApplicationListener

public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {

	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
		this.notificationAddress = notificationAddress;
	}

	public void onApplicationEvent(BlockedListEvent event) {
		// notify appropriate parties via notificationAddress...
	}
}

基于注释


使用`@EventListener` 注释在托管bean 的任何方法上注册事件监听器。重写如下:
public class BlockedListNotifier {

	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
		this.notificationAddress = notificationAddress;
	}

	@EventListener
	public void processBlockedListEvent(BlockedListEvent event) {
		// notify appropriate parties via notificationAddress...
	}
}

方法签名再次声明它所监听的事件类型,但是这一次使用了灵活的名称,并且没有实现特点的监听器接口。只要实际事件类型在它实现的层次结构中解析泛型参数,也可以通过泛型缩小事件类型范围。
也可以在注释本身指定事件类型 ,示例如下:

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
	// ...
}

还可以通过使用condition 定义表达式的注释的属性SpEL来添加额外的运行时过滤,该表达式应该匹配以实际调用特定事件的方法。
示例如下:

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlockedListEvent(BlockedListEvent blEvent) {
	// notify appropriate parties via notificationAddress...
}

SpEL 元数据:

Name Description
Event 实际的ApplicationEvent
Arguments array 用于调用该方法的参数(作为对象数组)。
Argument name 任何方法参数的名称。如果由于某种原因,名称不可用(例如,因为编译的字节代码中没有调试信息),则也可以使用#a<#arg>的语法来使用各个参数 ,其中<#arg> 代表参数索引(从 0 开始)。

异步


如果您希望特定的监听器异步处理事件,您可以重用 常规@Async 支持。示例如下:

@EventListener
@Async
public void processBlockedListEvent(BlockedListEvent event) {
	// BlockedListEvent is processed in a separate thread
}

使用异步事件时请注意以下限制:

如果异步事件监听器抛出异常,它不会传播到调用者。有关详细信息,请参阅 AsyncUncaughtExceptionHandler

异步事件监听器方法无法通过返回值来发布后续事件。如果您需要发布另一个事件作为处理结果,请注入 ApplicationEventPublisher 来手动发布该事件。

排序


如果您需要在另一个侦听器之前调用一个侦听器,则可以将`@Order` 注释添加到方法声明中,示例如下:
@EventListener
@Order(42)
public void processBlockedListEvent(BlockedListEvent event) {
	// notify appropriate parties via notificationAddress...
}

ApplicationEventMulticaster


ApplicationEventMulticaster接口功能主要用于广播事件给所有监听器,示例如下:
public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> var1);

    void addApplicationListenerBean(String var1);

    void removeApplicationListener(ApplicationListener<?> var1);

    void removeApplicationListenerBean(String var1);

    void removeAllListeners();

    void multicastEvent(ApplicationEvent var1);

    void multicastEvent(ApplicationEvent var1, @Nullable ResolvableType var2);
}

AbstractApplicationEventMulticasterApplicationEventMulticaster接口的抽象实现,提供监听器的监听器注册的方法。注册监听器时一般不允许相同监听器注册多个实例,因此使用Set集合,用于去重。然后实现广播事件的具体实现没有在这里实现,其他排序子类SimpleApplicationEventMulticaster去实现。

ApplicationEventPublisher


要发布自定义ApplicationEvent,请在ApplicationEventPublisher 上调用 publishEvent() 方法执行。通常,这是通过创建一个实现类 ApplicationEventPublisherAware并将其注册为 Spring bean 来完成的。示例如下:


public class EmailService implements ApplicationEventPublisherAware {

	private List<String> blockedList;
	private ApplicationEventPublisher publisher;

	public void setBlockedList(List<String> blockedList) {
		this.blockedList = blockedList;
	}

	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public void sendEmail(String address, String content) {
		if (blockedList.contains(address)) {
			publisher.publishEvent(new BlockedListEvent(this, address, content));
			return;
		}
		// send email...
	}
}

在这里插入图片描述

  如果喜欢的话,欢迎 									
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Spring 的相关文章

随机推荐

  • 召唤神龙打造自己的ChatGPT

    在之前的两篇文章中 我介绍了GPT 1和2的模型 并分别用Tensorflow和Pytorch来实现了模型的训练 具体可以见以下文章链接 1 基于Tensorflow来重现GPT v1模型 gzroy的博客 CSDN博客 2 花费7元训练自
  • 硬件系统工程师宝典(30)-----降压式Buck电路分析

    各位同学大家好 欢迎继续做客电子工程学习圈 今天我们继续来讲这本书 硬件系统工程师宝典 上篇我们说到DC DC变换中的开关调节模式有功耗小 效率高并且稳压范围宽的特点以及DC DC的指标参数和设计要求 今天我们来分析一下DC DC中的一个典
  • Flutter flutter.minSdkVersion的实际文件位置

    Flutter 项目的Android相关版本号配置 flutter minSdkVersion 的版本号配置文件实际路径 flutter sdk packages flutter tools gradle src main groovy f
  • 总结:linux笔记-004

    一 Linux network详解 1 linux中网路相关的主要的几个配置文件 etc hosts 配置主机名 域名 和IP地址的对应 etc sysconfig network 配置主机名和网关 etc sysconfig networ
  • 【服务器基础资源巡检,含常用命令解析】

    在工作中经常去搜这些命令解析 于是整理了一下供大家参考 一 内存占用 二 磁盘占用 三 CPU占用 一 内存占用 使用free指令会显示内存的使用情况 包括实体内存 虚拟的交换文件内存 共享内存区段 以及系统核心使用的缓冲区等 参数如下 b
  • Vue 3第三章:模板语法及指令介绍

    文章目录 1 插值表达式 1 1 声明变量可直接在模板中使用 采用 变量名称 的方式 1 2 模板语法支持三元表达式 1 3 模板语法支持运算 1 4 模板语法支持方法调用 2 指令 2 1 v bind 用于绑定属性或动态绑定对象的值到元
  • uniapp中开发小程序使用ref获取dom实例,一直显示undefined,竟然发现是这个原因!

    小程序是不能使用getElementById之类的dom api 所以考虑使用ref来获取dom元素 但事实上并不是如此 绑定ref后并没有输出我想要的dom元素 既然console log this refs iRef 为undefine
  • 简单易懂的Git回滚操作(reset、revert)

    简单易懂的Git回滚操作 reset revert 一 问题描述 二 背景知识 git的版本管理 及HEAD的理解 三 解决方法 方法一 git reset 具体操作 方法二 git revert 具体操作 一 问题描述 在利用github
  • 在命令行运行 VSCode(macOS)

    在命令行运行 VSCode macOS系统 Windows 版 VSCode 的安装脚本带着一个是否把 Code 加入 PATH 的选项 而 macOS版却没有 有的人想到给 VSCode 做一个符号链接加入 PATH 中 但实际上这样做会
  • IBM power小型机HMC管理口默认IP地址和ASMI默认密码

    IBM硬件管理控制台 Hardware Management Console 提供了标准的用户接口来配置和管理Power System系列服务器以及服务器上的分区 通过HMC软件可以管理服务器 POWER5 HMC控制地址 192 168
  • HCIP——BGP第一天实验

    一 实验要求 除R5的5 5 5 0环回外 其他所有环回均可互相访问 二 实验拓扑 三 实验过程 1 配置IP地址 R1 r1 int g0 0 1 r1 GigabitEthernet0 0 1 ip add 12 1 1 1 24 r1
  • STM32 电机教程 29 - 无刷无感入门1

    前言 无刷直流 Brushless Direct Current BLDC 电机是一种正快速普及的电机类型 它可在家用电器 汽车 航空航天 消费品 医疗 工业自动化设备和仪器等行业中使用 正如名称指出的那样 BLDC 电机不用电刷来换向 而
  • uvm的config_db

    config db 是用于在各个uvm对象里传递参数 一般参数类型 是interface int等 据说参数必须是静态类型 这个可以在uvm config db相关代码里确认 后来知道 config db还能设置sequence和seque
  • C#如何从数据库SQLServer中同时读取多个结果集

    当需要从数据库中同时读取多个结果集时 比如执行如下的sql语句 select from tblClass select from tblStudent 同时从两个表格中获取结果 会获取两个结果集 此时需要使用SqlDataReader对象的
  • vue使用threejs加载模型问题整理

    1 如果出现错误 THREE WebGLRenderer Error creating WebGL context 需要开启浏览器的gpu加速 GPU acceleration 地址栏输入 chrome flags ignore gpu b
  • 国考省考申论:归纳概括多个主体身上的优秀品质,透过动词现象(怎么做的),找到名词(精神品质)本质

    国考省考申论 归纳概括多个主体身上的优秀品质 透过动词现象 怎么做的 找到名词 精神品质 本质 2022找工作是学历 能力和运气的超强结合体 公务员特招重点就是专业技能 附带行测和申论 而常规国考省考最重要的还是申论和行测 所以大家认真准备
  • dede:list分页与控制文章标题显示字数

    关于dedecms分页 百度上也有许多教程 本人记性不好所以写个博客保存下来 pagesize控制每页显示条数 在 dede list 结束标签 后边写上 dede pagelist 标签即可 如何控制文章显示字 让溢出部分用 代替呢 其实
  • IPS与防火墙旁路部署

    一 防火墙旁路部署 实现防护功能的同时 可以完全不需改变用户的网络环境 并且可以避免设备对用户网络造成中断的风险 用于把设备接在交换机的镜像口或者接在 HUB 上 保证外网用户访问服务器的数据经过此交换机 并且设置镜像口的时候需要同时镜像上
  • iview+page封装+强制刷新

    前言 iview的page封装 缺点无法固定页码按钮数量 而且current的页面恢复选中第一个实现不了 这里动态写了强制刷新的方法 下面是组件cpage vue
  • 【Spring

    上篇 Spring 事件监听概述 对 Spring 事件监听的机制有了个基本的了解 本篇来详细的解读下Spring 的 事件监听机制 事件监听详解 ApplicationEvent ApplicationListener 基于注释 异步 排
Powered by Hwhale