首页 > 其他分享 >【Spring | 事件监听详解】

【Spring | 事件监听详解】

时间:2023-08-09 16:36:16浏览次数:42  
标签:String Spring void public 详解 事件 监听器 notificationAddress 监听

上篇 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...
	}
}

在这里插入图片描述

  如果喜欢的话,欢迎 

标签:String,Spring,void,public,详解,事件,监听器,notificationAddress,监听
From: https://blog.51cto.com/u_16111319/7022046

相关文章

  • 详解inline-block
    曾几何时,display:inline-block已经深入「大街小巷」,随处可见「display:inline-block;*display:inline;*zoom:1;」这样的代码。如今现代浏览器已经全面支持这个属性值了,上面的代码只是为了兼容IE6、7而已。那么你真的了解inline-block了吗?本文将带你深入剖析该属性值的前世......
  • SpringBoot源码实用场景:SpringBoot 3.1.0 环境下 PageHelper 1.4.0不生效问题排查
    1、技术栈:JDK17+SpringBoot3.1.0+PageHelper1.4.01<?xmlversion="1.0"encoding="UTF-8"?>2<project...>3<parent>4<groupId>org.springframework.boot</groupId>5<arti......
  • 老杜 JavaWeb 讲解(二十) ——Listener监听器
    (十八)Listener监听器引子:静态代码块packagecom.zwm.javaweb.servlet;/***@author猪无名*@date2023/8/81347*discription:*/publicclasstest2{//静态代码块在类加载时执行,并且只执行一次。//这个语法很简单,但什么时候用?很疑惑//假如,你希......
  • Spring Secriuty登录失败错误状态999重定向302
    原因是login.html登录页面有不能加载的静态资源,找出来去掉就好了,比如bootstrap.min.css环境使用SpringBootSecurity3做一个登录功能,使用了一个教程提供的HTML登录页面,代码如下SpringSecurity配置,自定义了登录页,资源都做了放行,能正常加载,使用数据库认证,正常查出@Configu......
  • 智慧工地源码,基于Vue+Spring Cloud +UniApp框架开发
    源码技术架构:微服务+JavaVue+SpringCloud+UniApp+MySql智慧工地管理平台是依托物联网、互联网、AI、可视化建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。智慧工地管理平台功能包括:劳务实名制管理系统、监测系统、区域安......
  • nacos的 Spring Security 身份认证绕过漏洞
     检测出了这个漏洞,但是nacos官方还没有升级文档,所以只能自行下载源码对 Spring-security -config的版本进行调整 如图,对原先的需要进行排除然后在引入漏洞以外的版本,因为是自己修改的,不确定升级版本是否会有未知的隐患,所以对版本是进行了降级的操作,需要修改的POM文件有两......
  • 本地内存跟踪NMT详解
    \本地内存跟踪NMT详解​1.Overview为什么java程序消耗的内存,远超-Xms、-Xmx的限制?因为各种原因,或是为了进行某些优化,JVM会额外分配内存。这些额外的分配,会导致java程序占用的内存,超出-Xmx的限制。本文档列举了通常情况下,JVM会分配哪几部分内存,以及各部分调整大小的方法。......
  • Apache HttpComponents Client详解
     ApacheHttpComponentsClient(也称为HttpClient)是一个开源的Java库,用于发送HTTP请求并处理HTTP响应。它提供了一组易于使用的API,用于构建和执行HTTP请求,并处理请求和响应的各个方面,如URL处理、请求头、请求体、响应状态、响应内容等。下面是一些关于使用ApacheHttpComponentsCl......
  • Apache HttpComponents Client详解
     ApacheHttpComponentsClient(也称为HttpClient)是一个开源的Java库,用于发送HTTP请求并处理HTTP响应。它提供了一组易于使用的API,用于构建和执行HTTP请求,并处理请求和响应的各个方面,如URL处理、请求头、请求体、响应状态、响应内容等。下面是一些关于使用ApacheHttpComponentsCl......
  • Apache HttpComponents Client详解
    ​ ApacheHttpComponentsClient(也称为HttpClient)是一个开源的Java库,用于发送HTTP请求并处理HTTP响应。它提供了一组易于使用的API,用于构建和执行HTTP请求,并处理请求和响应的各个方面,如URL处理、请求头、请求体、响应状态、响应内容等。下面是一些关于使用ApacheHttpCompone......