一、入门案例

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. 初探 Rust 语言与环境搭建

    1. Rust 简介 Rust 的历史 起源:Rust 语言最初由 Mozilla 研究员 Graydon Hoare 于 2006 年开始设计,并于 2009 年首次公开. 开发:Rust 是 Mo ...

  2. AutoFitTextureView Error inflating class

    报错: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解 ...

  3. 排除log4j-api ( 排除log4j )

    写法都一样,排除log4j,或者其相关的依赖 1. gradle: 1.1 判断是否有log4j a. 将war或jar解压后,搜索log4j b. 使用IDEA gradle菜单, 项目名-> ...

  4. 【YashanDB知识库】手动停止统计信息自动收集任务导致的性能变差

    [问题分类]功能使用 [关键字]统计信息收集 [问题描述]UAT对外演示环境因统计信息收集任务引起数据库整理性能变慢无应急处理手段 [问题原因分析] ● DROP_JOB程序用于删除一个非执行状态下的 ...

  5. Angular 18+ 高级教程 – Component 组件 の Control Flow

    前言 Control Flow 是 Angular v17 版本后推出的新模板语法,用来取代 NgIf.NgForOf.NgSwitch 这 3 个 Structure Directive. Stru ...

  6. java_day1_认识计算机,java环境,Java关键字、标识符、注释

    一.认识计算机 1.组成: 硬件:cpu,内存,显卡,... 软件: 系统软件:WPS, wegame, steam, IDEA,..... 应用软件:WPS, wegame, steam, IDEA ...

  7. 学好QT框架之后可以做什么工作?QT技术框架现代化行业大型复杂应用的经典成功案例

    简介 本文粗略的介绍了QT框架的软件开发技术生态体系的全球影响力:QT框架在文字办公领域.CAD三维图形领域.Linux操作系统领域.物联网领域.汽车电子领域以及数字医疗领域等现代化行业的大型复杂应用 ...

  8. P4036 [JSOI2008] 火星人

    #include <bits/stdc++.h> #define int long long using namespace std; int len; int m; int rt = 0 ...

  9. [OI] 整体二分

    整体二分可以理解成普通二分改版,其实并没有改多少,并且一般对 check() 函数的复杂度要求更宽松 先来看一道经典题目:求区间排名 给一个数列,若干组询问 \((l,r,k)\),求 \([l,r] ...

  10. 数据库日常实操优质文章分享(含Oracle、MySQL等) | 2023年2月刊

    本文为大家整理了墨天轮数据社区2023年2月发布的优质技术文章,主题涵盖Oracle.MySQL.PostgreSQL等数据库的环境搭建.故障处理等日常实践操作,以及概念梳理.常用脚本等总结记录,分享 ...