一、入门案例

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. .NET中各种线程同步锁

    编程编的久了,总会遇到多线程的情况,有些时候我们要几个线程合作完成某些功能,这时候可以定义一个全局对象,各个线程根据这个对象的状态来协同工作,这就是基本的线程同步. ​支持多线程编程的语言一般都内置了 ...

  2. “vscode #include 错误”的问题解决办法

    确定gcc没问题的情况下 打开这个文件 把linux下的文件直接复制过来 然后加上路径就OK了

  3. 从日志记一次Spring事务完整流程

    spring事务一次完整流程,创建 >确认获取连接 >完成 >提交>释放链接 DataSourceTransactionManager //Step1. 进入业务方法前,依据事 ...

  4. 【Azure Policy】使用deployIfNotExists 把 Azure Activity logs 导出保存在Storage Account

    问题描述 使用Azure Policy,对订阅下的全部Activity Log配置Diagnostic Setting,要求: 在Subscription或Management Group级别,针对未 ...

  5. sentinel中如何使用@SentinelResource和openFeign来进行服务熔断和降级的操作

    sentinel 前方参考 计算QPS-Sentinel限流算法 https://www.cnblogs.com/yizhiamumu/p/16819497.html Sentinel 介绍与下载使用 ...

  6. Hash表实践 —— 两数之和

    目录 题目背景 解题思路 题目背景 这个题目用常规的双循环就可以完成. 但不是最优解.为什么? 看看他的步骤数: N =[3,2,4] 求结果为6的两个元素坐标如下, 1). 3+2 = 5 不等于 ...

  7. SpringMVC —— 日期类型参数传递

    日期类型参数传递    相关注解    类型转换器   

  8. 系统编程-进程-ps命令、进程调度、优先级翻转、进程状态

    1.    ps详解 ps  : 只列出当前用户的进程 ps -ef : e表示有效, f 表示全面, 所以是列出后台的所有有效进程. ps -ef | more :   列出后台所有的有效进程,并且 ...

  9. 图解YUV420、YUV420(YUY2)、YUV422(YVYU)

    Y:亮度分量    UV:色度分量 1.  标准yuv指的是yuv420 一般看文章,会出现下面的公式,但不涉及具体的yuv格式,其实这一定指的是yuv420 Y与RGB的演算关系为:Y = 0.21 ...

  10. ConcurrentLinkedQueue详解(图文并茂)

    前言 ConcurrentLinkedQueue是基于链接节点的无界线程安全队列.此队列按照FIFO(先进先出)原则对元素进行排序.队列的头部是队列中存在时间最长的元素,而队列的尾部则是最近添加的元素 ...