别再面向 for 循环编程了,Spring 自带的观察者模式就很香!

【SpringBoot3】Spring Boot Event 自定义事件的发布与监听 Spring Boot自定义事件是Spring框架中事件处理机制的一种扩展,它允许开发者在Spring Boot应用程序中定义、发布和监听自己的事件。这些事件可以用于在应用程序的不同组件之间进行通信,实现解耦和异步处理。通过自定义事件,开发者可以更加灵活地处理业务逻辑,提高系统的可扩展性和可维护性。 阅读详情

1. 概述

在设计模式中,观察者模式是一个比较常用的设计模式。维基百科解释如下:

观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。
 
此种模式通常被用来实时事件处理系统。

在我们日常业务开发中,观察者模式对我们很大的一个作用,在于实现业务的解耦。以用户注册的场景来举例子,假设在用户注册完成时,需要给该用户发送邮件、发送优惠劵等等操作,如下图所示:

  • UserService 在完成自身的用户注册逻辑之后,仅仅只需要发布一个 UserRegisterEvent 事件,而无需关注其它拓展逻辑。
  • 其它 Service 可以自己订阅 UserRegisterEvent 事件,实现自定义的拓展逻辑。

友情提示:很多时候,我们会把观察者模式和发布订阅模式放在一起对比。
 
简单来说,发布订阅模式属于广义上的观察者模式,在观察者模式的 Subject 和 Observer 的基础上,引入 Event Channel 这个中介,进一步解耦。如下图所示:
 

2. Spring 事件机制

Spring 基于观察者模式,实现了自身的事件机制,由三部分组成:

  • 事件 ApplicationEvent:通过继承它,实现自定义事件。另外,通过它的 source 属性可以获取事件源,timestamp 属性可以获得发生时间。
  • 事件发布者 ApplicationEventPublisher:通过它,可以进行事件的发布。
  • 事件监听器 ApplicationListener:通过实现它,进行指定类型的事件的监听。

友情提示:JDK 也内置了事件机制的实现,考虑到通用性,Spring 的事件机制是基于它之上进行拓展。因此,ApplicationEvent 继承自 java.util.EventObject,ApplicationListener 继承自 java.util.EventListener。

3. 入门示例

示例代码对应仓库:lab-54-demo 。

看完一些基础的概念,我们来撸个 Spring 事件机制的入门示例,具体的场景还是以用户注册为例子。新建 lab-54-demo 项目,最终项目如下图:项目结构

3.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-54-demo</artifactId>

    <dependencies>
        <!-- 实现对 Spring MVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

引入 spring-boot-starter-web 依赖的原因,是稍后会提供示例 API 接口,方便测试。

3.2 UserRegisterEvent

创建 UserRegisterEvent 事件类,继承 ApplicationEvent 类,用户注册事件。代码如下:

public class UserRegisterEvent extends ApplicationEvent {

    /**
     * 用户名
     */
    private String username;

    public UserRegisterEvent(Object source) {
        super(source);
    }

    public UserRegisterEvent(Object source, String username) {
        super(source);
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

}

通过在 UserRegisterEvent 类中,定义成员变量 username,将用户名附带上。

3.3 UserService

创建 UserService 类,用户 Service。代码如下:

@Service
public class UserService implements ApplicationEventPublisherAware { // <1>

    private Logger logger = LoggerFactory.getLogger(getClass());

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void register(String username) {
        // ... 执行注册逻辑
        logger.info("[register][执行用户({}) 的注册逻辑]", username);

        // <2> ... 发布
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this, username));
    }

}

<1> 处,实现 ApplicationEventPublisherAware 接口,从而将 ApplicationEventPublisher 注入到其中。

<2> 处,在执行完注册逻辑后,调用 ApplicationEventPublisher 的 #publishEvent(ApplicationEvent event) 方法,发布「3.2 UserRegisterEvent」事件。

3.4 EmailService

创建 EmailService 类,邮箱 Service。代码如下:

@Service
public class EmailService implements ApplicationListener<UserRegisterEvent> { // <1>

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    @Async // <3>
    public void onApplicationEvent(UserRegisterEvent event) { // <2>
        logger.info("[onApplicationEvent][给用户({}) 发送邮件]", event.getUsername());
    }

}

<1> 处,实现 ApplicationListener 接口,通过 E 泛型设置感兴趣的事件。

<2> 处,实现 #onApplicationEvent(E event) 方法,针对监听的 UserRegisterEvent 事件,进行自定义处理。

【可以不加】<3> 处,锦上添花,设置 @Async 注解,声明异步执行。毕竟实际场景下,发送邮件可能比较慢,又是非关键逻辑。

友情提示:对 @Async 注解感兴趣的胖友,可以阅读《芋道 Spring Boot 异步任务入门》文章。

3.5 CouponService

创建 CouponService 类,优惠劵 Service。代码如下:

@Service
public class CouponService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @EventListener // <1>
    public void addCoupon(UserRegisterEvent event) {
        logger.info("[addCoupon][给用户({}) 发放优惠劵]", event.getUsername());
    }

}

<1> 处,在方法上,添加 @EventListener 注解,并设置监听的事件为 UserRegisterEvent。这是另一种使用方式!

3.6 DemoController

创建 DemoController 类,提供 /demo/register 注册接口。代码如下:

@RestController
@RequestMapping("/demo")
public class DemoController {

    @Autowired
    private UserService userService;

    @GetMapping("/register")
    public String register(String username) {
        userService.register(username);
        return "success";
    }

}

3.7 DemoApplication

创建 DemoApplication 类,应用启动类。代码如下:

@SpringBootApplication
@EnableAsync // 开启 Spring 异步的功能
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

3.8 简单测试

① 执行 DemoApplication 类,启动项目。

② 调用 http://127.0.0.1:8080/demo/register?username=yudaoyuanma 接口,进行注册。IDEA 控制台打印日志如下:

# UserService 发布 UserRegisterEvent 事件
2020-04-06 13:09:39.145  INFO 18615 --- [nio-8080-exec-1] c.i.s.l.eventdemo.service.UserService    : [register][执行用户(yudaoyuanma) 的注册逻辑]
# CouponService 监听处理该事件
2020-04-06 13:09:39.147  INFO 18615 --- [nio-8080-exec-1] c.i.s.l.eventdemo.service.CouponService  : [addCoupon][给用户(yudaoyuanma) 发放优惠劵]
# EmailService 监听处理该事件
2020-04-06 13:09:39.154  INFO 18615 --- [         task-1] c.i.s.l.eventdemo.service.EmailService   : [onApplicationEvent][给用户(yudaoyuanma) 发送邮件]

4. Spring 内置事件

在 Spring 框架中,自定义了非常多的自定义事件,让我们更容易的进行拓展。下面,我们来简单举一些例子。

4.1 ApplicationContextEvent

ApplicationContextEvent 是 Spring Context 相关的事件基类,如下图所示:

友情提示:Spring Context 可以简单理解成 IoC 容器。

  • ContextStartedEvent:Spring Context 启动完成事件。
  • ContextStoppedEvent:Spring Context 停止完成事件。
  • ContextClosedEvent:Spring Context 停止开始事件。
  • ContextRefreshedEvent:Spring Context 初始化或刷新完成事件。

也就是说,在 Spring Context 的整个生命周期中,会发布相应的 ApplicationContextEvent 事件。

SpringApplicationEvent 是 Spring Boot Application(应用)相关的事件基类,如下图所示:

  • ApplicationStartingEvent:Application 启动开始事件。
  • ApplicationEnvironmentPreparedEvent:Spring Environment 准备完成的事件。
  • ApplicationContextInitializedEvent:Spring Context 准备完成,但是 Bean Definition 未加载时的事件
  • ApplicationPreparedEvent:Spring Context 准备完成,但是未刷新时的事件。
  • ApplicationReadyEvent:Application 启动成功事件。
  • ApplicationFailedEvent:Application 启动失败事件。

也就是说,在 Application 的整个生命周期中,会发布相应的 SpringApplicationEvent 事件。

通过 ApplicationContextEvent 和 SpringApplicationEvent 事件,我们在《芋道 Spring Boot 持续交付 Jenkins 入门》文章的「3. 优雅上下线」小节中,实现了 Spring Boot + Nginx 的优雅上下线。

4.2 RouteRefreshListener

在《芋道 Spring Cloud 网关 Spring Cloud Gateway 入门》文章的「6. 基于配置中心 Nacos 实现动态路由」小节中,我们可以看到 Spring Cloud Gateway 通过监听 RefreshRoutesEvent 事件,结合 Nacos 作为配置中心,实现网关路由动态刷新的功能。

友情提示:Spring Cloud Zuul 也是通过监听 RoutesRefreshedEvent 事件,实现网关路由动态刷新的功能。

4.3 RefreshRemoteApplicationEvent

在《芋道 Spring Cloud 配置中心 Spring Cloud Config 入门》文章的「5. 自动配置刷新(第二弹)」小节中,我们可以看到 Spring Cloud Config Client 通过监听 RefreshRemoteApplicationEvent 事件,结合 RabbitMQ 作为 Spring Cloud Bus 消息总线,实现本地配置刷新的功能。

666. 彩蛋

至此,我们已经完成了对 Spring 事件机制的学习。当然,还有一些功能,胖友可以自己在倒腾倒腾。

① 如果胖友想要多个监听器按照指定顺序执行,可以通过实现 Ordered 接口,指定其顺序。

② 如果胖友想要监听多种 ApplicationContext 事件,可以实现 SmartApplicationListener 接口,具体示例可以看看 SourceFilteringListener 类。

③ @TransactionalEventListener 注解,可以声明在当前事务“结束”时,执行相应的监听逻辑。

④ 可以通过实现 ApplicationEventMulticaster 接口,定义自定义的事件广播器,可以往里面添加和移除监听器,并发布事件给注册在其中的监听器。使用比较少,基本可以忽略。

链接:https://juejin.cn/post/6948219095749951502

SpringBoot ApplicationEvent:事件发布与监听机制 *** 用户注册事件* 在用户注册成功后发布,用于执行后续操作*/// 用户ID// 用户名/*** 构造函数* @param source 事件源(发布事件的对象)* @param userId 注册用户ID* @param username 注册用户名*/这个例子定义了一个用户注册事件,它在用户注册成功后被发布,携带了用户ID和用户名信息,可以被其他组件监听并作出响应。 阅读详情

相关推荐

【Spring】Spring Boot 之事件(Event)ApplicationEvent

ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。如果将实现 ApplicationListener 接口的 bean 注入到上下文中,则每次使用 ApplicationContext 发布 ApplicationEvent 时,都会通知该 bean。本质上,这是标准的观察者设计模式。

九师兄 2065

Spring Boot:Spring Event的初步讲解

Spring提供了Event的功能,只要添加了spring-context依赖就可以引入,简单好用。 要使用Event只要准备三个部分: 事件类:定义事件,继承ApplicationEvent的类成为一个事件类。 发布者:发布事件,通过ApplicationEventPublisher发布事件。 监听者:监听并处理事件,实现ApplicationListener接口或者使用@EventListener注解 举个例子 定义发布者 事件源通常是某个业务类,当它处理完自身的业务

言尭的博客 5930

HEVC/VVC中R-Lambda码率控制算法原理

文章目录1. 比特分配1.1 GOP级比特分配1.2 帧级比特分配1.3 LCU级比特分配2. 码率控制2.1 λ的计算和更新2.2 参数QP的确定 VVC中码率控制算法沿用了HEVC中经典的R-λ码率控制模型,R-λ由中科大的李斌博士提出(详情参考JCTVC-K0103)。R-λ模型的基础为视频编码中 R(比特 bpp)和 D(失真 MSE)之间的双曲线模型,即 D(R)=CR−KD(R) = ...

Aidoneus_y 6137

秒懂SpringBoot之Spring Events全解析

相信即使是刚入门Java的小朋友们对事件(Event)也不会陌生,只要接触过消息队列,例如RabbitMq、Kafka等的都清楚。其思想和观察者这个设计模式类似,不懂的点击链接先学习一下前置知识。今天要谈论的Event是Spring给我们提供的一套类似的机制,某些场景下其有奇效,使你的技术水平立马绝尘于你的小伙伴们,装x成功是毫无疑问了…关于Spring Framwork 提供的事件机制就聊到这里了,其在日常开发过程中出境率还是挺高的,希望对后辈有所帮助。

ShuSheng007的程序人生 3395

Tribon Vitesse开发教程(一)

Tribon Vitesse简介 Tribon Vitesse是Tribon提供给Python编程语言的编程接口,它是一系列的API。使用Python的语法调用这些API,结合Python语言自身的语法生成的程序叫做Vitesse程序。Vitesse是法语“速度”的意思,读作“为戴斯”。使用Tribon Vitesse可以直接访问Tribon产品信息模型和使用Tribon应用程序的功能,以控制设计

forevermemory的专栏 2593

18650电池组流体直冷热管理仿真:COMSOL多物理场耦合建模路线与实战策略

在动力电池与储能系统的热管理设计中,多物理场耦合仿真已成为平衡性能与成本的关键工具。液冷方案的换热极限促使行业转向制冷剂直冷技术,而两相流与电池产热的强耦合特性,使得基于COMSOL的数值建模成为评估系统温升与流动分配的重要手段。工程实践中,电化学-热-流场全耦合模型与集总电池-流场简化模型各有适用场景,前者揭示电池内部微观机理,后者则以高计算效率支撑包级方案迭代。通过合理简化几何、标定内阻与熵热系数、设置等效换热边界,仿真能够准确预测直冷系统在快充或大倍率放电下的温度均匀性与压降特性,从而指导流道优化与制

weixin_33585822的博客 314

Spring 自带的观察者模式使用

别再面向 for 循环编程了,Spring 自带的观察者模式就很香!

qq_43050847的博客 387

激光三角测量法:斜射与直射式技术的原理与应用解析

本文深入解析激光三角测量法中斜射式与直射式技术的原理、应用及对比。斜射式适用于高精度小范围测量,尤其擅长处理反光表面;直射式则适合大范围位移检测,结构更简单。文章详细介绍了两种技术的光路分析、数学建模、应用场景及选型建议,并探讨了系统校准与误差分析方法,为工业检测领域提供实用参考。

weixin_29280219的博客 414

观察者模式——Spring中使用

前言 观察者模式在 Spring 中的应用 观察者模式,在目标对象发出动作后,触发事件,观察者接收事件,然后执行对应操作。 步骤 观察者模型。 参考博客。看大佬博客写的文档学习。 思维导图。画图讲解清楚流程。(待定) 学习方法。怎么样学习。 注意点。 pom 依赖。 Main 方法编写。 Controller 层。Http 请求发送使用 register 层。编写事件类。 service 层,目标对象,事件创建、发送类。 service 层,观察者对象1,事件接收、执行类。 service 层,

u010798073的博客 429

SSD盘符漂移导致OSD down场景模拟与恢复

运维团队反馈一个问题,现象是:某个OSD对应的cache分区发生了变化,比如原来cache使用的分区是/dev/sde,后来还是这块盘,但分区信息不知何故,变成了/dev/sdf(产品OSD设备并不是根据分区名称来map,而是根据partlabel),最终的现象是这个OSD down了,没法启动.接到这个现象的反馈后,记录一下这个问题在lab的复现方法。

Gavin Blog 938

华为OD机试2025A卷 - BOSS的收入(Java & Python& JS & C++ & C )

华为OD机试2025A卷 - BOSS的收入(Jav一个XX产品行销总公司,只有一个boss,其有若干一级分销,一级分销又有若干二级分销,每个分销只有唯一的上级分销。规定,每个月,下级分销需要将自己的总收入(自己的+下级上交的)每满100元上交15元给自己的上级。现给出一组分销的关系,和每个分销的收入,请找出boss并计算出这个boss的收入。输入:分销关系和收入:[[分销id 上级分销id 收入], [分销id 上级分销id 收入], [分销id 上级分销id 收入]]输出:[boss的ID, 总收入]

算法大师! 1172

Spring Boot 事件机制 Event 入门

Spring Boot 事件机制 Event 入门

CHENFU_ZKK的博客 2747

Cesium 场景特效之【全球海洋】GL2兼容版

Cesium 场景特效之【全球海洋】GL2兼容版

喜欢钻研前端和分享技术 1278

SpringBoot 3 Event 个人详细总结

JDK17类描述封装装事件发布功能的接口可以管理多个ApplicationListener对象并向其发布事件的对象实现的接口,一个典型的例子就是,实现了接口,并在其内部实现中,使用了作为实际发布事件的发布者。实现了接口,它是Spring Event 体系的实际发布者: Application Event listeners监听器接口,在Spring 6.1之后添加了方法,来控制该监听器是否支持异步执行,默认是true,支持异步执行。是的子类,它对非的类进行了封装,使得可以在各个监听器中进行事件传播。

2401_87705025的博客 2012

OpenClaw实战系列03:Slack/Telegram国际版接入实战指南

在当今的软件开发和工作流自动化中,将项目管理工具与即时通讯平台集成已成为提高团队协作效率的关键。OpenClaw作为一个开源的自动化工具,通过接入Slack和Telegram国际版,可以实现实时通知、自动化任务触发和团队协作的无缝对接。本文将详细介绍如何实现OpenClaw与这两个主流即时通讯平台的集成。OpenClaw是一个开源的自动化工作流引擎,支持多种触发器和执行器,能够帮助开发团队实现CI/CD流程、任务调度、监控告警等自动化场景。模块化设计:支持插件化扩展多触发器支持。

PeterPan的博客 587

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

没错,这就是 SpringBoot Event的工作原理!

Component@Override本文我们详细地介绍了SpringBoot事件机制的原理、核心源码以及实际使用方法。通过运用事件机制,我们可以更好地实现解耦合和异步处理,为项目的可维护性和扩展性提供支持。

stone_tmp的博客 1223

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

SpringBoot 事件机制 Event 入门

1.背景 在设计模式中,观察者模式是一个常用的设计模式: 观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。 此种模式通常被用来实时事件处理系统。 在我们日常业务开发中,观察者模式对我们很大的一个作用,在于实现业务的解耦。以用户注册的场景来举例子,假设在用户注册完成时,需要给该用户发送邮件、发送优惠劵等等操作,如下图所示: UserService 在完成自身的用户注册逻辑之后,仅仅只

Jarvis's Blog 2031

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring Boot中使用SpringEvent组件

3.发布事件,要在某个组件中注入ApplicationEventPublisher,并调用其publishEvent方法。:发布事件的对象,通常是Spring的应用上下文(ApplicationContext)。:事件是应用中发生的重要事情,通常是一个继承自ApplicationEvent的类。:监听并处理事件的对象,通常是实现了ApplicationListener接口的类。注:condition 限制只接收filter开头的消息。

weixin_48965172的博客 1188

Spring Event事件用法 Spring Boot Event事件发布和订阅 Spring Event事件发布 Spring Event事件订阅

1、本文总结了 Spring Event事件的用法和代码案例,可以发布普通对象和ApplicationEvent对象事件,同理可以监听 对应的两种事件。日常开发中,建议使用@EventListener 注解监听事件,功能更强大。启动完成事件。停止完成事件。停止开始事件。ContextRefreshedEvent:Spring Context 初始化或刷新完成事件。

HaHa_Sir的博客 5715

Spring Boot 事件机制 Event 入门到精通

本文详细介绍了SpringBoot事件驱动编程机制,主要内容包括:1)事件驱动编程基础概念和优势;2)Spring事件体系核心架构与传播流程;3)SpringBoot内置事件序列和使用示例;4)自定义事件开发实践,包括基础事件和泛型事件定义;5)多种事件监听方式实现,包括注解和接口方式;6)高级特性如异步处理、事务监听、顺序控制和错误处理;7)测试策略和性能监控方案;8)生产环境最佳实践配置。文章通过完整代码示例展示了如何利用SpringBoot事件机制构建松耦合、可扩展的应用程序架构。

油墨香^-^的博客 1016

SpringBoot - 事件机制使用详解(ApplicationEvent、ApplicationListener)

Spring 事件机制使用观察者模式来传递事件和消息。我们可以使用 ApplicationEvent 类来发布事件,然后使用 ApplicationListener 接口来监听事件。当事件发生时,所有注册的 ApplicationListener 都会得到通知。事件用于在松散耦合的组件之间交换信息。由于发布者和订阅者之间没有直接耦合,因此可以在不影响发布者的情况下修改订阅者,反之亦然。下面通过样例样式事件机制的使用。

航行博客 3835
上一篇: 面试官问我:你确定JVM堆内存是共享的?
下一篇: 阿里P9力荐Spring Boot学习笔记,一步一步学习Spring Boot,学到的不单单是基础
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值