当前位置: 首页 > news >正文

SpringBoot - Google EventBus、AsyncEventBus

介绍

EventBus 顾名思义,事件总线,是一个轻量级的发布/订阅模式的应用模式,最初设计及应用源与 google guava 库。

相比于各种 MQ 中间件更加简洁、轻量,它可以在单体非分布式的小型应用模块内部使用(即同一个JVM范围)。

我们也可以把它和 MQ 中间件结合起来使用,使用 EventBus 作为当前应用程序接收中间件 MQ 消息的统一入口,然后应用内部基于 EventBus 进行分发订阅,以达到高内聚低耦合的目的(当应用内部需要消费多种不同 MQ 中间件消息时,不需要在当前应用的好多不同代码位置都编写 MQ 消费代码)。

EventBus 整体设计和流程比较简单,由注册、发布和订阅三个要点组成,如下:
在这里插入图片描述

注意事项

本文对 google guava 库中的 EventBus 进行实例说明,注意事项要先进行特别说明。

  • EventBus 默认为同步调用,同一个 EventBus 中注册的多个订阅处理,再事件下发后是被总线串行逐个调用的,如果其中一个方法占用事件较长,则同一个 EventBus 中的其他事件处于等待状态,且发送消息事件的代码调用处也是同步调用等待的状态。
  • 同一个 EventBus 对象,不仅仅在同一个 post 调用中串行执行,在多次并发 post 调用时,多个 post 调用之间也是串行等待执行的关系,这个要特别注意,应用不当会导致严重的消息消费处理性能瓶颈问题!

所以推荐使用异步的方式处理,异步处理主要包括 “EventBus 使用线程池统一异步” 和 “订阅消费处理代码自己使用线程异步” 两种方式。这里我更推荐使用前者,因为后者对开发者有一定的要求,加入开发者某个耗时的业务订阅实现没有自行使用线程异步处理,则会影响其他处的订阅处理。

代码示例

1、添加 pom 依赖

        <!-- google EvengBus 在 guava 包中 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.2-jre</version></dependency><!-- lombok 非必须,其作用你懂得 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope></dependency>

2、创建一个Java接口用于自动注册

package com.example.demospringbean.eventbus;/*** 用于自动注册事件订阅类的接口* * @author shanhy* @date 2023-08-30 12:06*/
public interface EventBusListener {
}

3、编写总配置类

package com.example.demospringbean.eventbus;import com.google.common.eventbus.EventBus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.List;/*** EventBus 配置类** @author shanhy* @date 2023-08-30 11:11*/
@Configuration
public class EventBusConfiguration {/*** 实例化 EventBus 对象,并自动注册所有订阅类对象** @param eventListenerList 所有实现了 EventBusListener 接口的实现类* @return*/@Beanpublic EventBus eventBus(List<EventBusListener> eventListenerList){// 异步处理,按照自己需要,实现自己的 Executor 逻辑,例如为了防止线程长期占用需要增加超时机制等
//      EventBus eventBus = new AsyncEventBus(new Executor() {
//            public void execute(Runnable command) {
//                new Thread(command).start();
//            }
//        });EventBus eventBus = new EventBus();if(eventListenerList != null && !eventListenerList.isEmpty()) {eventListenerList.iterator().forEachRemaining(eventListener -> eventBus.register(eventListener));}return eventBus;}}

4、编写订阅测试类

package com.example.demospringbean.eventbus;import com.google.common.eventbus.Subscribe;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** @author shanhy* @date 2023-08-30 11:19*/
@Component
public class EventSub1 implements EventBusListener {@Subscribepublic void handlerEvent(String test) {System.out.println("11111>>>>>" + test);}@Subscribepublic void handlerEvent2(String test) throws InterruptedException {TimeUnit.SECONDS.sleep(5);System.out.println("22222>>>>>" + test);}}
package com.example.demospringbean.eventbus;import lombok.Builder;
import lombok.Data;/*** @author shanhy* @date 2023-08-30 13:19*/
@Data
@Builder
public class User {private String name;private int age;}
package com.example.demospringbean.eventbus;import com.google.common.eventbus.Subscribe;
import org.springframework.stereotype.Component;/*** @author shanhy* @date 2023-08-30 11:19*/
@Component
public class EventSub2 implements EventBusListener {@Subscribepublic void handlerEvent(String test){System.out.println("33333>>>>>" + test);}@Subscribepublic void handlerEvent2(User user){System.out.println("44444>>>>>" + user.getName());}}

5、编写消息事件发送测试

package com.example.demospringbean;import com.example.demospringbean.eventbus.User;
import com.google.common.eventbus.EventBus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 接口示例** @author shanhy* @date 2023-03-20 15:49*/
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate EventBus eventBus;@GetMapping("/testEvent1")public String testEvent1(){eventBus.post("Hello");return "OK";}@GetMapping("/testEvent2")public String testEvent2(){eventBus.post(User.builder().name("Tome").age(22).build());return "OK";}
}

代码说明:

1、以上代码使用的 EventBus、未使用 AsyncEventBus,并加入了线程 sleep,是为了运行代码可以观察其串行处理效果(浏览器开2个Tab同时调用 /testEvent1 观察输出),让你能更明显的感受到这种处理会给程序带来多大的性能问题(推荐实际业务生产中使用 AsyncEventBus)。

2、@Subscribe 注解修饰的事件处理方法,其参数和发送事件时的消息体会自动按类型关联对应。只有相同类型的消息体才会被消费处理。例如示例中 /testEvent1 接口发送的 “Hello” 字符串,不会触发 handlerEvent2(User user) 方法的执行,同理执行示例中 /testEvent2 接口发送 User 对象时,只会触发 handlerEvent2(User user) 方法。


(END)

相关文章:

SpringBoot - Google EventBus、AsyncEventBus

介绍 EventBus 顾名思义&#xff0c;事件总线&#xff0c;是一个轻量级的发布/订阅模式的应用模式&#xff0c;最初设计及应用源与 google guava 库。 相比于各种 MQ 中间件更加简洁、轻量&#xff0c;它可以在单体非分布式的小型应用模块内部使用&#xff08;即同一个JVM范围…...

Tauri打包windows应用配置中文界面

使用 Tauri Rust 开发桌面应用&#xff0c;在 windows 系统上&#xff0c;打包后安装包名称后缀、安装界面、相关说明默认都是英文的。如果要默认显示为中文&#xff0c;则需要在 tauri.conf.json 中配置相应参数。 前言 默认情况下&#xff0c;在 windows 系统打完的 mis 包…...

深度丨Serverless + AIGC,一场围绕加速创新的升维布局

作者&#xff1a;褚杏娟 上图来源于基于函数计算部署 SD实现光影效果 前言&#xff1a; Serverless 在中国发展这些年&#xff0c;经历了高潮、低谷、现在重新回到大众视野。很多企业都非常感兴趣&#xff0c;部分企业开始大规模应用&#xff1b;也有一些企业对在生产环境真正…...

flask日志

您可以使用 Python 自带的 logging 模块来实现 Flask 日志记录功能。以下是一个简单的示例&#xff1a; import os import logging from logging.handlers import TimedRotatingFileHandler from flask import Flask, requestapp Flask(__name__)# 创建日志目录 if not os.pa…...

新能源汽车动力总成系统及技术

需要动力系统总成的请联&#xff1a;shbinzer 拆车邦 需要动力系统总成的请联&#xff1a;shbinzer 拆车邦 需要动力系统总成的请联&#xff1a;shbinzer 拆车邦 需要动力系统总成的请联&#xff1a;shbinzer 拆车邦 需要动力系统总成的请联&#xff1a;shbinzer …...

在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速

在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速 0. 背景 0.1 起源 生产环境都是在 k8d pod 中运行&#xff0c;直接在容器中开发不好嘛&#xff1f;每次换电脑&#xff0c;都要配配配&#xff0c;呸呸呸新电脑只安装日常用的软件不好嘛&…...

模拟实现应用层协议

模拟实现应用层协议 文章目录 模拟实现应用层协议应用层再谈协议 序列化和反序列化 网络版计算器自定义协议利用Json进行序列化和反序列化json库的安装条件编译 应用层 应用层&#xff08;Application layer&#xff09;是OSI模型的第七层。应用层直接和应用程序接口并提供常见…...

SAP-MM-冲销凭证布局变更

业务场景&#xff1a; 仓管员在冲销物料凭证时MBST&#xff0c;显示行很少&#xff0c;只有7行&#xff0c;提出需求调整布局为多行&#xff0c;但是MBST没有调整布局功能&#xff0c; 解决&#xff1a;点击“定制本地布局-选项-字体设置”调整字体大小 跟据需求调整字体&…...

事务方法中保证数据只插入一次方案探究

需求场景 在项目的接口请求中&#xff0c;我们有一个接口A需要事务支持&#xff0c;在接口A中调用了方法B&#xff0c;方法B也需要事务支持&#xff0c;两者都带有Transactional注解。在B方法中是这个一个逻辑&#xff0c;查询本地数据库是否包含属性值为一个特定值的字段&…...

高通开发系列 - 5G网络之QTI守护进程服务介绍

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 返回:专栏总目录 目录 代码位置和依赖关系功能介绍代码逻辑讲解外设节点关注的目录socket服务端初始化DPM客户端监听守护关键的数据结构体…...

Ansible学习笔记3

ansible模块&#xff1a; ansible是基于模块来工作的&#xff0c;本身没有批量部署的能力&#xff0c;真正具有批量部署的是ansible所运行的模块&#xff0c;ansible只是提供一个框架。 ansible支持的模块非常多&#xff0c;我们并不需要把每个模块记住&#xff0c;而只需要熟…...

DP读书:鲲鹏处理器 架构与编程(十)鲲鹏软件生态与云服务

十秒带你了解鲲鹏软件生态与云服务 鲲鹏软件生态与云服务ARM授权机制在传统的PC领域&#xff0c;半导体厂商的业务类型主要分为两种&#xff1a;在移动领域&#xff0c; ARM服务器生态鲲鹏服务器软件生态1. 鲲鹏计算产业2. 鲲鹏软件生态兼容性3. openEluer操作系统4. 鲲鹏软件栈…...

CSS_IOS适配状态栏和IOS底部安全区域

状态栏 var(--status-bar-height)计算属性 height: calc(var(--status-bar-height) 343px);底部安全区 先constant再env constant(safe-area-inset-bottom) env(safe-area-inset-bottom)计算属性 height: calc(132px constant(safe-area-inset-bottom)); height: calc(1…...

中央仓库更新失败,IDEA报错repository is non-nexus repo, or does not indexed

某个仓库未被识别为 Nexus 仓库&#xff0c;或者没有被正确地索引。导致引入依赖一直爆红&#xff0c;找不到。只有本地仓库的依赖没报错&#xff0c;因为下载过了&#xff0c;添加新的依赖就需要到远程仓库找就爆红。 解决 去阿里云Maven官网看了一下&#xff0c;发现阿里云…...

设计模式--代理模式

笔记来源&#xff1a;尚硅谷Java设计模式&#xff08;图解框架源码剖析&#xff09; 代理模式 1、代理模式的基本介绍 1&#xff09;代理模式&#xff1a;为一个对象提供一个替身&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象2&#xff09;这样做的好处是…...

链路聚合原理

文章目录 一、定义二、功能三、负载分担四、分类五、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、定义 在网络中&#xff0c;端口聚合是一种将连接到同一台交换机的多个物理端口捆绑在一起&#xff0c;形成一个逻辑端口的技术。通过端口聚合&…...

el-table表尾添加合计行,自动合计,且特殊列自定义计算展示

效果如图 1.element-ui的table表格有合计功能&#xff0c;但是功能却不完善&#xff0c;会有不显示和计算出现错误的问题&#xff0c;项目中有遇到&#xff0c;所以记录下 show-summary&#xff1a;自动合计 getSummaries&#xff08;&#xff09;&#xff1a;对合计行进行特…...

uview ui 1.x ActonSheet项太多,设置滚动(亲测有效)

问题&#xff1a;ActionSheet滚动不了。 使用uview ui &#xff1a;u-action-sheet, 但是item太多&#xff0c;超出屏幕了&#xff0c; 查了一下文档&#xff0c;并没有设置滚动的地方。 官方文档&#xff1a;ActionSheet 操作菜单 | uView - 多平台快速开发的UI框架 - uni-a…...

STM32 Cubemx 同名外设中断及回调

文章目录 前言示例工程个人理解 前言 最近在学习STM32&#xff0c;采用HAL库开发方式。记录一下同名外设中断及回调。 这里提及的同名外设指USART1/2之类的相同外设&#xff0c;但不是同一个instance。 示例工程 以使用cubemx配置两个同名外设EXTI0/EXT4为例。 在NVIC配置…...

储能辅助电力系统调峰的容量需求研究(matlab代码)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《储能辅助电力系统调峰的容量需求研究》&#xff0c;是一个很常规很经典的matlab优化代码&#xff0c;主要是对火电、风电和储能等电力设备主体进行优化调度&#xff0c;在调峰能力达不到时采…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...