Spring-Event入门实践及执行原理

news/2024/11/14 13:31:22/文章来源:https://www.cnblogs.com/sun-10387834/p/18543518

一、入门案例

1. 添加依赖
首先,在 pom.xml 文件中添加 Spring Boot 和 Spring Event 的依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

2. 定义自定义事件
创建一个自定义事件类 CustomEvent,继承自 ApplicationEvent:

package com.example.demo.event;import org.springframework.context.ApplicationEvent;public class CustomEvent extends ApplicationEvent {private String message;public CustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}

3. 创建事件监听器
创建一个事件监听器类 CustomEventListener,实现 ApplicationListener 接口:

package com.example.demo.listener;import com.example.demo.event.CustomEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("Received custom event - " + event.getMessage());}
}

4. 发布事件
在 DemoApplication 类中,注入 ApplicationEventPublisher 并发布自定义事件:

package com.example.demo;import com.example.demo.event.CustomEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationEventPublisher;@SpringBootApplication
public class DemoApplication implements CommandLineRunner {@Autowiredprivate ApplicationEventPublisher publisher;public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@Overridepublic void run(String... args) throws Exception {CustomEvent event = new CustomEvent(this, "Hello, Spring Event!");publisher.publishEvent(event);}
}

5. 运行应用
运行 DemoApplication 类,启动 Spring Boot 应用程序。你应该会在控制台看到以下输出:

收到:com.sun.springevent.SpringEventApplication$$SpringCGLIB$$0@6e3ecf5c消息;时间:1731466981066;消息:Hello, Spring Event!

二、Spring-Event执行原理

Spring Event 机制是 Spring 框架中的一个事件驱动模型,用于在应用程序的不同组件之间进行解耦和通信。下面是 Spring Event 的执行原理的详细解释:

1. 事件 (Event)
  定义:事件是应用程序中发生的一个特定动作或状态变化。
  实现:在 Spring 中,事件通常是由一个继承自 ApplicationEvent 的类表示的。例如,我们之前定义的 CustomEvent 就是一个自定义事件。
2. 事件发布者 (Event Publisher)
  定义:事件发布者是负责创建并发布事件的组件。
  实现:在 Spring 中,可以通过 ApplicationEventPublisher 接口来发布事件。通常,这个接口会通过依赖注入的方式注入到需要发布事件的类中。
3. 事件监听器 (Event Listener)
  定义:事件监听器是负责处理事件的组件。
  实现:在 Spring 中,可以通过实现 ApplicationListener 接口或者使用 @EventListener 注解来定义事件监听器。
4. 事件传播过程
  1、事件创建:
    事件发布者创建一个 ApplicationEvent 的实例,并传递必要的参数。
  2、事件发布:
    事件发布者调用 ApplicationEventPublisher 的 publishEvent 方法,将事件对象传递给 Spring 容器。
  3、事件分发:
    Spring 容器接收到事件后,会查找所有注册了该事件类型的监听器。
    Spring 容器会调用每个监听器的 onApplicationEvent 方法(如果使用 ApplicationListener 接口)或带有 @EventListener 注解的方法。
  4、事件处理:
    监听器接收到事件后,根据事件的内容执行相应的业务逻辑。
5. 异步事件处理
  默认行为:Spring 事件默认是同步处理的,即事件发布者会等待所有监听器处理完事件后才会继续执行后续代码。
  异步处理:可以通过配置 ApplicationEventMulticaster 来实现异步事件处理。通常,可以在 application.properties 或 application.yml 中配置 TaskExecutor 来实现异步处理。
6. 示例代码解释
  CustomEvent:定义了一个自定义事件类,继承自 ApplicationEvent,并添加了一个 message 属性。
  CustomEventListener:定义了一个事件监听器类,实现了 ApplicationListener<CustomEvent> 接口,并重写了 onApplicationEvent 方法来处理事件。
  DemoApplication:主类,实现了 CommandLineRunner 接口,在 run 方法中创建并发布了一个 CustomEvent 事件。


总结
  Spring Event 机制通过事件发布者、事件监听器和事件本身,实现了组件之间的松耦合和灵活的事件驱动架构。通过这种方式,可以更容易地管理和扩展应用程序的功能。

 

三、深入地探讨publisher.publishEvent(event) 背后的具体执行流程和机制。

1. 事件发布方法 publishEvent

当你调用 ApplicationEventPublisher 的 publishEvent 方法时,Spring 容器会执行一系列操作来处理这个事件。以下是详细的步骤:

1.1 调用 publishEvent 方法

publisher.publishEvent(event);

1.2 AbstractApplicationContext 中的 publishEvent 方法

ApplicationEventPublisher 接口的实现类通常是 AbstractApplicationContext,它是 Spring 容器的核心类之一。

AbstractApplicationContext 中的 publishEvent 方法会调用 doPublishEvent 方法来处理事件。

public void publishEvent(ApplicationEvent event) {assertContextActive();getApplicationEventMulticaster().multicastEvent(event);
}

2. 事件多播器 ApplicationEventMulticaster

ApplicationEventMulticaster 是负责将事件广播给所有注册的监听器的组件。默认情况下,Spring 使用 SimpleApplicationEventMulticaster 实现。

2.1 multicastEvent 方法

SimpleApplicationEventMulticaster 的 multicastEvent 方法会遍历所有注册的监听器,并调用它们的 onApplicationEvent 方法。

@Override
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);}}
}

3. 事件监听器调用

3.1 invokeListener 方法

invokeListener 方法会调用具体的监听器方法来处理事件。

private void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler == null) {doInvokeListener(listener, event);} else {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}
}private void doInvokeListener(ApplicationListener<?> listener, ApplicationEvent event) {try {// 调用监听器的 onApplicationEvent 方法
        listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg = ex.getMessage();if (msg == null || matchesClassName(ex, event.getClass(), msg) ||matchesClassName(ex, ResolvableType.forInstance(event).getRawClass(), msg)) {String className = listener.getClass().getName();if (logger.isWarnEnabled()) {logger.warn("Non-matching event type for listener [" + className + "]");}}else {throw ex;}}
}

4. 异步事件处理

4.1 配置 TaskExecutor

如果希望事件处理是异步的,可以在 application.properties 或 application.yml 中配置 TaskExecutor。例如:

spring:task:execution:pool:core-size: 5max-size: 10queue-capacity: 100

4.2 自定义 ApplicationEventMulticaster

也可以通过自定义 ApplicationEventMulticaster 来实现更复杂的事件处理逻辑。例如:

@Configuration
public class EventConfig {@Beanpublic ApplicationEventMulticaster applicationEventMulticaster() {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());return eventMulticaster;}
}

5. 事件监听器的注册

5.1 通过 @Component 注解

可以使用 @Component 注解将监听器类注册为 Spring 管理的 Bean。

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("Received custom event - " + event.getMessage());}
}

5.2 通过 @EventListener 注解

也可以使用 @EventListener 注解来定义事件监听器方法。

@Component
public class CustomEventListener {@EventListenerpublic void handleCustomEvent(CustomEvent event) {System.out.println("Received custom event - " + event.getMessage());}
}

总结
  通过上述步骤,我们可以看到 publisher.publishEvent(event) 背后的详细执行流程。Spring 容器通过 ApplicationEventMulticaster 将事件广播给所有注册的监听器,并调用它们的 onApplicationEvent 方法来处理事件。此外,Spring 还提供了异步事件处理和自定义事件多播器的能力,以满足更复杂的应用需求。

 

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

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

相关文章

大厂SSP的Java学习路线

大厂SSP的Java学习路线,零基础,分阶段,极简的自学编程指南,全网最全面最贴心 小厂(入门阶段)怎么学,中厂(进阶阶段)怎么学,大厂(高级阶段)怎么学现在互联网环境这么差,Java还能学吗? 学Java还能找到工作吗? 大家好呀, 我是程序员回家养猪, 一个专升本, 三段实习经历拿…

章节一、Maven学习

一、maven介绍 1、简介 Maven是一个项目管理工具(构建工程、管理jar包、编译代码、完成测试、项目打包) Maven是基于POM(project object model 项目对象模型)实现的 Maven标准化了项目结构 Maven提供了一个免费的中央仓库 开源jar包 Maven是跨平台的 2、作用 一键构建:编译…

[GYCTF2020]Blacklist 1

[GYCTF2020]Blacklist 1 打开实例发现get提交框,提交1发现显示尝试万能密码无果尝试联合注入,显示出了过滤规则,可以见到很多关键字都被过滤了尝试堆叠注入,成功显示出数据表 ?inject=1;show databases;查表 ?inject=1;use ctftraining;show tables;看到了个FLAG_TABLE查…

Serverless GPU:助力 AI 推理加速

本文将探讨云原生 Serverless GPU 如何从根本上解决这些问题,以实现 AI 技术的高效落地。本文整理自 2024 云栖大会,阿里云智能集团高级技术专家聂大鹏、NVIDIA 解决方案架构师金国强演讲议题《Serverless GPU:助力 AI 推理加速》 近年来,AI 技术发展迅猛,企业纷纷寻求将 …

HyperWorks的shrink warp meshing

在HyperWorks中,针对某些具有复杂几何特征的零部件的网格剖分,Altair HyperMesh 向用户提供了一种名为 Shrink Warp Meshing 的技术,快捷高效地完成有限元模型前处理工作。例如在车辆碰撞分析研究中,用户可以使用 Shrink Warp Meshing 技术快速构建诸如传动系统等(具有复杂…

快速了解电源模块的使用方法 BDB10-12W系列电源模块

快速了解电源模块的使用方法 BDB10-12W系列电源模块电源是整个电路可靠工作的核心部分。然而,由于电源电路的电流和发热量较大,容易出现故障。今天我为大家介绍一下电源模块的使用方法。BOSHDIA电源模块是将电源电路集成到一个很小的PCB板上,从而实现输出稳定电压和大电流的…

GSDml结构

1. 如何方便的看到GSDml的结构在github上找到一个很好用的开源工具以及它的开源汉化,叫xml notepad,可以很好的看到设备树视图。 [2.9.0.8官方下载地址] [汉化插件]2. 文件结构总体就是header和Body两个部分ISO15745Profile | +--ProfileHeader +--ProfileBody|+--DeviceIdent…

什么是CRM系统?CRM系统在企业中扮演什么角色?

近年来,客户关系管理(CRM)系统逐渐显露头角,成为企业把握航向、驶向成功的关键。也有好多人来问关于这方面的问题,所以专门开一篇文章为大家深入了解CRM系统的含义、功能、价值以及它在现代企业中的实际应用,为的呀就是帮助大家全面把握这一概念。 一、CRM系统是什么? 客…

运行 MainApplication 时出错 运行 MainApplication 时出错。命令行过长。 通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行

运行springboot的启动类时,报了这个错。 解决办法: 1、修改选项2、添加缩短命令行项3、选择JAR清单

python 垃圾回收

引用计数器#define PyObject_HEAD PyObject ob_base; #define PyObject_VAR_HEAD PyVarObject ob_base;// 宏定义,包含 上一个、下一个,用于构造双向链表用。(放到refchain链表中时,要用到) #define _PyObject_HEAD_EXTRA \struct _object *_ob_next;标记清除 分…

作业4

作业①: 要求: 熟练掌握 Selenium 查找HTML元素、爬取Ajax网页数据、等待HTML元素等内容。 使用Selenium框架+ MySQL数据库存储技术路线爬取“沪深A股”、“上证A股”、“深证A股”3个板块的股票数据信息。 候选网站:东方财富网:http://quote.eastmoney.com/center/gridlist…

采集opc da 转 profinet IO项目案例

VFBOX协议转换网关支持PLC,modbus,EthernetIP,Profinet,CCLink,EtherCAT,IEC61850,IEC104,bacnet,DLT645,HJ212,opc ua,opc da,DNP3。目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 应用条件 2 4 查看OPC DA服务器的相关参数 2 5 配置网关采集opc da数据 4 6 用prof…