SpringBoot Event,事件驱动轻松实现业务解耦

什么是事件驱动

  • Spring 官方文档
  • AWS Event Driven

简单来说事件驱动是一种行为型设计模式,通过建立一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都能自动接收通知并更新。即将自身耦合的行为进行拆分,使拆分出的行为根据特定的状态变化(触发条件)自动触发。

事件驱动核心组件

  1. 被观察者(Subject): 负责维护观察者列表,并在状态变化时通知观察者。被观察者可以是一个类或对象。
  2. 观察者(Observer): 定义一个更新接口,使得在状态变化时能够接收被观察者的通知。观察者对象需要注册到被观察者上,以便接收通知。
  3. 通知(Notify): 被观察者在状态变化时会调用观察者的更新方法,通知它们有关状态的变化。
  4. 订阅(Subscribe)和取消订阅(Unsubscribe): 观察者可以通过订阅和取消订阅操作来注册和注销对被观察者的关注。

实现方式

  • Guava
  • Spring Event

版本依赖

  • JDK 17
  • Spring Boot 3.2.0
  • Guava 33.0.0-jre

image-20231226033126185

Tips

在仅将事件拆分出事件对象与事件监听对象后,通过事件总线推送事件,仍是单线程执行,在SpringBoot中需要两个注解来实现异步执行。

  • @EnableAsync 类注解,在配置类上标记开启SpringBoot异步线程
  • @Async 方法注解,表示注解的方法异步执行。@Async 注解的方法仅在通过容器中获取的对象调用方法为异步执行,非容器对象方法调用无效

导入依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>33.0.0-jre</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>

基于Guava实现

创建事件对象

import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** Guava 实现事件对象*/
@Data
public class GuavaEvent implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private String data;public GuavaEvent(String data) {this.data = data;}
}

创建事件监听

import com.google.common.eventbus.Subscribe;
import com.yiyan.study.guava.event.GuavaEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** Guava 事件监听*/
@Component
@Slf4j
public class GuavaEventListener {@Subscribe@Asyncpublic void onEvent(GuavaEvent event) throws InterruptedException {// 模拟业务耗时Thread.sleep(500);log.info("Guava - GuavaEvent onEvent : {}", event.getData());}
}

创建事件总线,并注册事件监听

import com.google.common.eventbus.EventBus;
import com.yiyan.study.guava.listener.GuavaEventListener;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** Guava 事件总线*/
@Configuration
public class GuavaEventBus {@Resourceprivate GuavaEventListener guavaEventListener;@Beanpublic EventBus initialize() {EventBus eventBus = new EventBus();// 注册监听eventBus.register(guavaEventListener);return eventBus;}
}

编写Controller测试接口

import com.google.common.eventbus.EventBus;
import com.yiyan.study.guava.event.GuavaEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** 事件测试Controller*/
@Slf4j
@RestController
public class EventController {@Resourceprivate EventBus eventBus;@GetMapping("/event/guava")public void guavaPost(@RequestParam(value = "message") String message) {StopWatch stopWatch = new StopWatch("guava-event");stopWatch.start();eventBus.post(new GuavaEvent(message));stopWatch.stop();log.info("guava-event Request Log: \r{}", stopWatch.prettyPrint());}
}

基于Spring Event实现

Spring Boot自己维护了一个ApplicationEventPublisher的事件注册Bean,通过@EventListener注解标识监听事件。无需自己在注册一个消息总线。

创建事件对象

import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** Spring 事件对象*/
@Data
public class SpringEvent implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private String data;public SpringEvent(String data) {this.data = data;}
}

注册监听对象

import com.yiyan.study.spring.event.SpringEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** Spring event listener*/
@Component
@Slf4j
public class SpringEventListener {@EventListener@Asyncpublic void onApplicationEvent(SpringEvent event) throws InterruptedException {// 模拟业务耗时Thread.sleep(500);log.info("SpringEvent received: {}", event.getData());}
}

补充测试接口

package com.yiyan.study.controller;import com.google.common.eventbus.EventBus;
import com.yiyan.study.guava.event.GuavaEvent;
import com.yiyan.study.spring.event.SpringEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** 事件测试Controller*/
@Slf4j
@RestController
public class EventController {@Resourceprivate EventBus eventBus;@Resourceprivate ApplicationEventPublisher eventPublisher;@GetMapping("/event/guava")public void guavaPost(@RequestParam(value = "message") String message) {StopWatch stopWatch = new StopWatch("guava-event");stopWatch.start();eventBus.post(new GuavaEvent(message));stopWatch.stop();log.info("guava-event Request Log: \r{}", stopWatch.prettyPrint());}@GetMapping("/event/spring")public void springPublish(@RequestParam(value = "message") String message) {StopWatch stopWatch = new StopWatch("spring-event");stopWatch.start();eventPublisher.publishEvent(new SpringEvent(message));stopWatch.stop();log.info("spring-event Request end: \r{}", stopWatch.prettyPrint());}
}

测试

在这里插入图片描述

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

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

相关文章

@click 默认传递原生的事件对象

项目场景 [Day1] <template><div id"app"><h1>小黑记事本</h1><button click"handleClick">www</button><div class"head"><!-- 按键&#xff08;回车&#xff09;按下&#xff0c;出发add事件&…

Leetcode---376周赛---中位数贪心

题目列表 2965. 找出缺失和重复的数字 2966. 划分数组并满足最大差限制 2967. 使数组成为等数数组的最小代价 2968. 执行操作使频率分数最大 一、找到缺失和重复的数字 由于数据范围不是很大&#xff0c;可以直接暴力统计每个数字出现的次数&#xff0c;时间复杂度为O(n^2…

【Java中序列化的原理是什么(解析)】

&#x1f341;序列化的原理是什么&#xff1f; &#x1f341;典型-----解析&#x1f341;拓展知识仓&#x1f341;Serializable 和 Externalizable 接门有何不同? &#x1f341;如果序列化后的文件或者原始类被篡改&#xff0c;还能被反序列化吗?&#x1f341;serialVersionU…

【SpringCloud笔记】(9)分布式配置中心之Config

Config 概述 分布式系统当前面临的配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务&#xff0c;每个服务的粒度相对较小&#xff0c;因此系统中会出现大量的服务。 比如&#xff1a;有n个微服务连接同一套数据库&#xff0c;当连接数据库需要发生变动时&…

Exploring the Limits of Masked Visual Representation Learning at Scale论文笔记

论文名称&#xff1a;EVA: Exploring the Limits of Masked Visual Representation Learning at Scale 发表时间&#xff1a;CVPR2023 作者及组织&#xff1a;北京人工智能研究院&#xff1b;华中科技大学&#xff1b;浙江大学&#xff1b;北京理工大学 GitHub&#xff1a;http…

ARM串口通信编程实验

完成&#xff1a;从终端输入选项&#xff0c;完成点灯关灯&#xff0c;打开风扇关闭风扇等操作 #include "gpio.h" int main() {char a;//char buf[128];uart4_config();gpio_config();while(1){//接收一个字符数据a getchar();//发送接收的字符putchar(a);switch(…

redis复习笔记01(小滴课堂)

高并发的必备两大“核技术”队列和缓存 介绍本地缓存和分布式缓存 Nosql介绍和Reidis介绍 Linux服务器源码安装Redis6和相关依赖 在路径下上传压缩包。 上传压缩包。 版本更新了&#xff0c;但这是临时的。 版本更新了。 解压压缩包&#xff1a; 重命名&#xff1a; 我们可以看…

C# WPF上位机开发(MySql访问)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们学习了数据库sqlite&#xff0c;不过这是一种小型的数据库&#xff0c;作为内部使用还可以。但是&#xff0c;如果要与外面的其他供应商进…

蓝牙物联网在智慧医疗中的应用

物联网技术开启了万物互联的时代&#xff0c;并且随着智慧城市建设的加速推进及物联网技术对各行业的逐步渗透&#xff0c;“智慧”概念应运而生&#xff0c;诸如智慧能源、智慧交通、智慧医疗等“遍地开花”&#xff0c;可以说&#xff0c;物联网技术给各行业带来了产业模式上…

Arduino/Android 蓝牙通信系统设计解决方案

随着当今安全管理的发展需求以及国家对安全监控行业的支持&#xff0c;这几年&#xff0c;安全监控行业发展迅猛&#xff0c;各类监控系统百花齐放。传统的温度监控系统通过有线或其他方式传送温度数据&#xff0c;而本文提出了利用蓝牙无线传输数据的设计方案&#xff0c;这种…

FLStudio21中文版水果编曲软件好用吗?如何下载最新版本

FL Studio21版是一款在国内非常受欢迎的多功能音频处理软件&#xff0c;我们可以通过这款软件来对多种不同格式的音频文件来进行编辑处理。而且FL Studio 21版还为用户们准备了超多的音乐乐器伴奏&#xff0c;我们可以直接一键调取自己需要的音调。 FL Studio21版不仅拥有非常…

金和OA C6 gethomeinfo sql注入漏洞

产品介绍 金和网络是专业信息化服务商,为城市监管部门提供了互联网监管解决方案,为企事业单位提供组织协同OA系统开发平台,电子政务一体化平台,智慧电商平台等服务。 漏洞概述 金和 OA C6 gethomeinfo接口处存在SQL注入漏洞&#xff0c;攻击者除了可以利用 SQL 注入漏洞获取…

vue3+ts pinia存储及持久化

index.ts 需要安装pinia-plugin-persist npm i pinia-plugin-persist -Simport { createPinia} from "pinia" // 引入批量的pinia持久存储插件 import piniaPluginPersist from pinia-plugin-persist const storecreatePinia(); store.use(piniaPluginPers…

【网络安全 | 网络协议】结合Wireshark讲解TCP三次握手

TCP三次握手在Wireshark数据包中是如何体现的&#xff1f;在此之前&#xff0c;先熟悉TCP三次握手的流程。 TCP三次握手流程 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的传输层协议。在建立 TCP 连接时&#xff0c;需要进行三次握手&#xff0c;防止因为…

【自然语言处理】用Python从文本中删除个人信息-第二部分

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

uni-app pages.json之globalStyle全局页面样式配置

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

STM32软硬件CRC测速对比

硬件CRC配置 以及软硬件CRC速度对比 使用CUBEMX配置默认使用的是CRC32&#xff0c;从库中可以看出这一点 HAL库提供了以下两个计算函数 HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength); 这个函数用于在已有的CRC校验结果的基础上累积…

听GPT 讲Rust源代码--src/tools(26)

File: rust/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs 在Rust源代码中&#xff0c;iter_out_of_bounds.rs文件是Clippy lints库的一部分&#xff0c;该库用于静态代码分析&#xff0c;用于检测Rust代码中的潜在问题和错误。iter_out_of_bounds.rs文件中…

第三天:对ThreadLocal理解

ThreadLocal是什么&#xff1f; ThreadLocal&#xff0c;也就是线程本地变量。如果你创建了一个 ThreadLocal变量&#xff0c;那么访问这个变量的每个线程都会有这个变量的一个本地副本&#xff0c;多个线程操作这个变量的时候&#xff0c;实际是操作自己本地内存里面的变量&a…

5G NTN与“手机直连卫星”快速原型

5G非地面网络(5G NTN) 5G非地面网络(Non-Terrestrial Network, NTN)是一项旨在使5G用户终端(5G UE)连接到 位于卫星上的非地面基站(5G gNB)的技术NTN是3GPP R17版本的重要功能&#xff0c;在5G-Advanced中持续演进&#xff0c;已成为3GPP Release 18 工作计划中的重要组成部分…