后端视角看 EventBus:发布订阅总线的原理、场景与用法
大家好我是程序员天天困。今天聊一个能让你少写一大堆回调的东西——EventBus一个在 Android 和 Java 里都挺火的事件发布订阅库。我自己做后端多一些但这东西在 Android 用得最广所以咱们两边都照顾着讲争取你写哪端都能用得上。话不多说直接开始。一、EventBus 到底是干什么的EventBus 不是什么新发明它就是把「发布-订阅」模式做成一个开箱即用的总线让两个模块不用互相认识就能通信。EventBus发布订阅事件总线greenrobot 出品的开源库用发布-订阅模式解耦组件通信——发布者只管把事件丢进总线订阅者通过注解方法接收两者互不持有引用。你可以把它理解成「代码里的广播站」。广播站的比喻最贴切拿话筒的人喊一嗓子所有调到这个频道的接收器都能听到喊的人根本不用知道谁在听。回到后端你写 Spring 时用过的EventListener配ApplicationEventPublisher或者 Guava 的EventBus乃至 Kafka、RabbitMQ都是同一套发布订阅思想的不同重量级实现。EventBus 是其中最轻的一个一个约 60k 的 jar不依赖任何中间件在进程内同步或异步分发延迟在微秒级。它的运行机制简单到一句话发布者调post把事件丢进 EventBusEventBus 根据事件类型查到所有订阅了这个类型的方法依次调用。就这么直接发布者不关心谁来收订阅者也不关心谁发的。二、为什么需要它组件通信的痛那有人就会问了Android 自己不是有通信机制吗为啥还要再造一个 EventBus这得先看看原生的那套东西痛在哪。Android 想让组件之间传消息最常用的就两样Handler 和 BroadcastReceiver。Handler 用来切线程、投递消息BroadcastReceiver 用来发系统级广播。能用是能用但写起来烦——一堆样板代码不说发消息的还得知道收消息的是谁两边经常要互相持有引用组件一多引用关系就缠成一团。最常见的场景你在子线程里跑接口请求数据回来要刷新 UI得拿 Handler 切回主线程两个 Fragment 要互换数据得借 Activity 当中间人或者写个 Listener 接口回调。项目小的时候忍忍就过去了业务一膨胀这种回调套回调、引用套引用的写法代码量和耦合度一起失控。后端其实一个毛病——Service 之间互相Autowired最后织成一张谁也拆不动的网根子都是发布者把「我要通知谁」写死在了自己代码里。EventBus 的解法很简单A 不认识 B/C/D它只认识 EventBus。谁关心谁自己订阅发布者彻底从「通知谁」里解放出来新增一个订阅者发布者一行代码都不用改。下面这张图把两种方式摆在一起——左边是组件之间互相持有引用、回调层层传递右边是发布者只对总线 post订阅者各自从总线取谁也不认识谁。可能有人会问那我后端直接上 Kafka、RabbitMQ 不就完了为啥还要一个进程内的 EventBus两者解决的不是同一个量级的问题。MQ 是跨进程、跨机器的异步消息带持久化和集群EventBus 是单进程内的方法调用级通信没有网络、没有序列化开销延迟在微秒级。同一个 JVM 内部模块解耦上 MQ 是杀鸡用牛刀跨服务通信EventBus 又鞭长莫及。各管一段别混用。三、三步上手在 Spring Boot 里用 EventBusEventBus 的全部 API 浓缩成三步——定义事件、注册订阅、发送事件背下来就能用。它不绑 AndroidSpring Boot 后端一样能跑把依赖换成eventbus-java就行。如果你团队已经定了用 EventBus或者要和 Android 端共用一套事件模型下面这套 Spring Boot 写法直接抄至于要不要在 Spring 里上它选型建议放在第六节。第一步引入 Maven 依赖。在pom.xml里加这一段!-- 以 Maven Central 3.3.1 为准Spring Boot 2.x 注解用 javax3.x 用 jakarta --dependencygroupIdorg.greenrobot/groupIdartifactIdeventbus-java/artifactIdversion3.3.1/version/dependency第二步定义事件 写订阅者。事件就是一个普通 POJO不继承任何基类订阅者用Subscribe标注接收方法方法必须 public、有且仅有一个参数publicclassLoginEvent{privatefinalStringusername;publicLoginEvent(Stringusername){this.usernameusername;}publicStringgetUsername(){returnusername;}}ComponentpublicclassUserModule{Subscribe(threadModeThreadMode.POSTING)publicvoidonLogin(LoginEventevent){System.out.println(用户 event.getUsername() 已登录);}PostConstruct// Bean 启动时注册publicvoidinit(){EventBus.getDefault().register(this);}PreDestroy// Bean 销毁时注销publicvoiddestroy(){EventBus.getDefault().unregister(this);}}把订阅者声明成 Spring 的Component再用PostConstruct注册、PreDestroy注销register 和 unregister 就跟着 Bean 生命周期自动成对不用你手动记着去调。第三步发送事件。在任何 Service 里直接 post发布者完全不需要知道谁在监听ServicepublicclassLoginService{publicvoidlogin(Stringusername){// 业务处理……EventBus.getDefault().post(newLoginEvent(username));}}我见过太多线上 OOM根因就是register了却没unregister——EventBus 持有订阅者引用对象回收不掉。所以哪怕图省事也务必让注册和注销跟着生命周期走别只 register 不注销。下面这张时序图展示了从post到被订阅方法处理的完整链路发布者 post 后EventBus 按事件类型查订阅表再按线程模式决定同步直调还是丢进线程池。四、Subscribe 三个关键参数线程模式、粘性事件、优先级Subscribe注解的三个参数不是花架子它们决定了事件在哪个线程跑、能不能收到「早到」的事件、谁先收到。SubscribeEventBus 的订阅方法注解标注「这个方法要接收什么类型的事件」可指定线程模式、是否粘性、优先级。被注解的方法要求 public 修饰、有且仅有一个参数。粘性事件Sticky EventpostSticky发出后会被 EventBus 缓存下来的事件之后新注册的订阅者也能收到它。你可以理解成「迟到的订阅者也能拿到上一条广播」。线程模式ThreadMode决定了订阅方法在哪个线程被执行。纯 Java 后端主要用 POSTING 和 ASYNCMAIN 系列依赖 Android 主线程后端用不到ThreadMode在哪执行纯 Java 能用典型场景POSTINGpost 所在线程直接同步调用能不耗时的事件最常用ASYNC永远丢进线程池异步执行能订阅者要做耗时 IOBACKGROUNDpost 在主线程则入池在子线程则直接调能轻量后台任务MAINAndroid 主线程执行否更新 UIMAIN_ORDERED主线程按顺序非阻塞否多个 UI 更新串行粘性事件有个坑要单独说缓存的粘性事件不会自动消失重复postSticky同类型会覆盖旧的但如果你忘了removeStickyEvent换场景后新订阅者可能收到一条本不该收的「历史事件」。我的习惯是粘性事件用完立刻removeStickyEvent别让缓存兜着脏数据。优先级priority是个 int数字越大越先收到且只在同一线程模式下才有意义。五、什么场景下用 EventBusEventBus 适合「一对多、发布者不想知道订阅者是谁」的场景不适合「调用方需要返回值」或「强顺序依赖」的场景。后者本质上是在做方法调用硬套事件总线只会让链路更难追踪。几类典型场景全局状态广播登录登出、网络断连恢复——一处 post多处 UI 或模块各自响应。跨层组件通信Fragment 之间、Fragment 与 Activity、Service 与页面不再借 Activity 中转。后端模块解耦领域事件的轻量版——下单成功后通知积分、库存、推送模块各自处理下单服务不关心下游有谁。配置热更新配置中心拉到新值后 post 一个ConfigChangedEvent各模块自己刷新。可能有人会问后端真要用 EventBus 吗还是直接 SpringEventListener更香老实说纯 Spring 后端我更推荐用 Spring 自带的EventListener零额外依赖、和容器生命周期天然集成、还支持TransactionalEventListener跟着事务走。EventBus 的甜区在 Android 和非 Spring 的纯 Java 工程——没有 Spring 容器、又想要个轻量发布订阅它比手撸观察者模式省心。要是跨进程老老实实上 MQ。六、后端视角的取舍EventBus vs Guava vs Spring选哪个看你在不在 Spring 容器里、要不要跨进程、对依赖体积多敏感。方案依赖线程模型跨进程适合谁greenrobot EventBus~60k jarThreadMode 五种否Android / 非 Spring 纯 JavaSpring 里也能跑Guava EventBusGuava 整包同步或异步二选一否已用 Guava 的纯 Java 项目Spring EventListenerSpring 容器同步可配异步否任何 Spring 后端Kafka / RabbitMQ独立中间件异步是跨服务、跨进程EventBus 也不是银弹几个老问题一直都在事件类会越定义越多一个项目几十个 Event 类很常见订阅方法靠反射查找编译时索引能优化但要配 annotation processor忘了unregister就内存泄漏最麻烦的是事件流难追踪——post一条事件到底谁会响应、什么顺序得全局搜调试链路偏长。这些都是它换来解耦的代价。写法上以 Maven Central 的org.greenrobot:eventbus:3.3.12021 年最后大版本为准长期稳定。Android 新项目也有人用 Kotlin 的 Flow / Channel 替代但就「最快上手、几行解耦」而言EventBus 依然是门槛最低的方案之一。后端要不要上 EventBus我的判断就一句在 Spring 里别折腾EventListener已经够用写 Android 或纯 Java 又想轻量解耦EventBus 依然是几行代码搞定、最省心的那个。跨进程的事交给 MQ别让一条进程内总线去干它不该干的活。

相关新闻

role仓库之Galaxy

role仓库之Galaxy

Ansible Galaxy 是官方统一角色仓库平台:https://galaxy.ansible.com 类似于GitHub,我们可以在这个平台上搜索别人写好的roles,然后下载到本地使用。 核心命令: 在线搜索 nginx 相关角色 ansible-galaxy search nginx 查看角色详情…

2026/7/24 9:04:29 阅读更多 →
OCR C++ Tesseract监控识别进度(多线程)

OCR C++ Tesseract监控识别进度(多线程)

这个程序使用C标准多线程库监控Tesseract OCR的识别进度。输入图片&#xff1a;程序运行后会在CMD里打印识别结果&#xff1a;第一行打印识别进度&#xff0c;在up的电脑上只从1%加载到61%,就开始打印输出结果了。代码&#xff1a;#include <tesseract/baseapi.h> #inclu…

2026/7/22 2:10:47 阅读更多 →
OCR C++ Tesseract检测图像的倾斜角度

OCR C++ Tesseract检测图像的倾斜角度

这个程序使用Tesseract OCR检测图像的页面布局信息&#xff0c;包含图像的倾斜角度等信息。输入图片稍微有一点点倾斜&#xff1a;运行程序之后会在CMD里输出检测结果&#xff1a;方向0表示图片没有旋转。书写方向0表示从左到右。文本行顺序2表示文本的阅读顺序是从上到下、从左…

2026/7/22 9:49:56 阅读更多 →

最新新闻

【向量Milvus】---- Docker部署Milvus向量数据库 保姆级教程

【向量Milvus】---- Docker部署Milvus向量数据库 保姆级教程

文章目录 一、前言 &#x1f4d6;二、Milvus是什么 &#x1f9e0;三、应用场景 &#x1f310;四、下载安装 &#x1f680;环境前提步骤1&#xff1a;下载编排文件步骤2&#xff1a;启动Milvus服务步骤3&#xff1a;查看运行状态步骤4&#xff1a;常用运维命令 五、实战案例 &am…

2026/7/24 13:24:38 阅读更多 →
AI 怎样改变我们的生活和职业?Anthropic 经济指数报告给出的真实数据

AI 怎样改变我们的生活和职业?Anthropic 经济指数报告给出的真实数据

查睡觉建议凌晨 3 点最火、报税截止日前一天咨询量暴涨 8 倍、把任务整包交给 AI 的人反而最乐观……这些不是段子&#xff0c;而是 Anthropic 最新一期《经济指数报告&#xff08;Cadences&#xff09;》里的真实发现。 2026 年 6 月 26 日&#xff0c;Anthropic 发布了新一期…

2026/7/24 13:24:38 阅读更多 →
RetinaNet在药盒日期识别中的优化与应用

RetinaNet在药盒日期识别中的优化与应用

1. 项目概述&#xff1a;当药盒遇上RetinaNet 上周整理家庭药箱时&#xff0c;我盯着十几个药盒上模糊的保质期数字发了愁。这种场景想必大家都不陌生——药品过期风险、用药安全隐患往往就藏在这些难以辨认的小字里。这正是我们开发"基于RetinaNet的智能药盒日期识别系统…

2026/7/24 13:24:38 阅读更多 →
2026在线视频图片去水印网站怎么用?不限次数免费无需下载教程

2026在线视频图片去水印网站怎么用?不限次数免费无需下载教程

日常整理个人素材、剪辑自用内容、留存平台优质图文视频时&#xff0c;水印往往会影响画面观感&#xff0c;很多用户都在寻找适配手机、电脑、鸿蒙等多端&#xff0c;无需安装软件、操作简单的免费去水印方案。2026年市面主流去水印工具分为在线网页工具和免安装小程序工具两类…

2026/7/24 13:24:38 阅读更多 →
如何筛选无外机厨房空调供应商?

如何筛选无外机厨房空调供应商?

选购无外机厨房空调&#xff0c;核心原则是&#xff1a;先确认安装环境&#xff0c;再评估产品性能&#xff0c;最后看服务能力。本文仅提供行业通用的选型方法&#xff0c;不推荐任何具体品牌或产品&#xff0c;仅以美尔凯特厨房专用空调为例&#xff0c;按统一标准拆解其参数…

2026/7/24 13:24:38 阅读更多 →
AI健康科普系统:从知识过滤到个性化推荐

AI健康科普系统:从知识过滤到个性化推荐

1. 项目背景与核心价值去年夏天&#xff0c;我在三甲医院营养科做用户调研时发现个有趣现象&#xff1a;候诊区80%的年轻人都在刷短视频看健康科普&#xff0c;但问到具体内容时&#xff0c;多数人却说"刷到就信了"。这种信息过载与专业度缺失的矛盾&#xff0c;催生…

2026/7/24 13:23:38 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化&#xff0c;核心特色&#xff1a;三维 X/Y/Z 三轴空间&#xff0c;所有散点分布在 0~10 立方体空间内&#xff1b;散点使用径向渐变实现立体 3D 圆球质感&#xff1b;支持鼠标 / 触屏拖拽画布&#xff0c;…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls&#xff1a;进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值&#xff0c;并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好&#xff0c;我是一名编程初学者&#xff0c;同时这也是我编程学习之路上的第一篇博客。在这里&#xff0c;我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手&#xff0c;目前在学习c语言&#xff0c;我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中&#xff0c;我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源&#xff0c;还是配置文件、证书等&#xff0c;都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下&#xff0c;但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP&#xff08;轻量级目录访问协议&#xff09;作为企业级身份认证的黄金标准&#xff0c;已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时&#xff0c;发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”&#xff0c;而是以可解释、可审计、可迭代的方式&#xff0c;赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻