一、入门案例

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> {
@Override
public 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 { @Autowired
private ApplicationEventPublisher publisher; public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} @Override
public 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: 5
max-size: 10
queue-capacity: 100

4.2 自定义 ApplicationEventMulticaster

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

@Configuration
public class EventConfig { @Bean
public 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> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event - " + event.getMessage());
}
}

5.2 通过 @EventListener 注解

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

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

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

Spring-Event入门实践及执行原理的更多相关文章

  1. Spring Validation最佳实践及其实现原理,参数校验没那么简单!

    之前也写过一篇关于Spring Validation使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂Spring Validation.本文会详细介绍Spring Validation各种场景下 ...

  2. Spring Boot 入门实践

    一.Eclipse配置Spring Boot环境 1.查看eclipse版本信息: 2.登录:http://spring.io/tools/sts/all 看eclipse对应的插件版本对应的ecli ...

  3. Spring Boot WebFlux 快速入门实践

    02:WebFlux 快速入门实践 Spring Boot 2.0 spring.io 官网有句醒目的话是: BUILD ANYTHING WITH SPRING BOOT Spring Boot ( ...

  4. Spring Boot WebFlux-01——WebFlux 快速入门实践

    第01课:WebFlux 快速入门实践 Spring Boot 2.0 spring.io 官网有句醒目的话是: BUILD ANYTHING WITH SPRING BOOT Spring Boot ...

  5. Spring MVC执行原理

    spring的MVC执行原理 1.spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求 进行真正的处理工作. 2.DispatcherSer ...

  6. spring的MVC执行原理

    spring的MVC执行原理 1.spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求 进行真正的处理工作. 2.DispatcherSer ...

  7. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  8. 《Spring Boot 入门及前后端分离项目实践》系列介绍

    课程计划 课程地址点这里 本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 个部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 项目实践开发 ...

  9. 《Spring Boot 入门及前后端分离项目实践》目录

    开篇词:SpringBoot入门及前后端分离项目实践导读 第02课:快速认识 Spring Boot 技术栈 第03课:开发环境搭建 第04课:快速构建 Spring Boot 应用 第05课:Spr ...

  10. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

随机推荐

  1. vscode使用说明

    # 要经常保存 # centos打开vscode方式 普通用户:[bw@localhost ~]$ /usr/share/code/bin/code 超级用户:[root@localhost shar ...

  2. ubuntu 16.04 安装Python3.8虚拟环境

    virtualenv为应用提供了隔离的Python运行环境,可以解决不同应用间多版本的冲突问题. virtualenv会把用户指定版本的python复制到虚拟环境下,并修改相关的环境变量,使得pyth ...

  3. redux开发中的一个小坑

    redux的actiontypes,不可以重名,重名将会报错 When called with an action of type "inserttoken", the slice ...

  4. Adobe Photoshop cc2022 Mac中文破解版下载安装

    PS2024 for Mac,我这个版本是Mac版25.2,大小4.03G,支持intel/M1/M2/M3芯片,最低系统需求:13.4以上,不限速下载地址还是放在最后. 然后安装总共有三个步骤,尤其 ...

  5. 详谈怎样配置微信小程序的分包以解决体积过大问题(转载)

    一.文件结构和工具功能 1.小程序编译的文件结构 非常必要推荐了解小程序文件结构,对于稍大的项目,对于包的精简会起到柳暗花明又一村的效果 .众所周知,微信小程序分为"主包"和&qu ...

  6. PlugIR:开源还不用微调,首尔大学提出即插即用的多轮对话图文检索 | ACL 2024

    即插即用的PlugIR通过LLM提问者和用户之间的对话逐步改进文本查询以进行图像检索,然后利用LLM将对话转换为检索模型更易理解的格式(一句话).首先,通过重新构造对话形式上下文消除了在现有视觉对话数 ...

  7. 把dataframe 一列转成 array

    把dataframe 一列转成 array

  8. 画流程图、状态图、时序图、甘特图的JS库-mermaid-js

    参考地址:https://github.com/mermaid-js/mermaid 原生使用方式: <!DOCTYPE html> <html> <head> & ...

  9. Figma 学习笔记 – Auto Layout

    用途 Auto Layout 有点像 CSS 的 Flex, 它还带有 responsive 的概念.使用它以后可以替代掉不少 constraints 的写法. 用法 一个 parent 抱着多个 c ...

  10. 图形化客户端工具——Navicat

    1.下载 下载地址:https://wwb.lanzoub.com/i4TuZ0g3okod   破解:     解压后有两个文件          先点击第一个文件依次安装     安装完成后    ...