Java泛型事件总线通过将事件类型作为泛型参数实现精确分发,避免运行时反射与字符串匹配,确保编译期类型安全、无强制转换、IDE自动补全,且不同泛型参数的同名事件互不干扰。

Java 中泛型在事件总线中实现不同事件类型的精确分发,关键在于把“事件类型”本身作为泛型参数,而不是用 Object 或字符串做运行时标识。这样能让编译器参与类型检查,避免转型错误、反射开销和拼写失误。
用泛型事件类替代通用事件接口
所有事件统一实现一个空标记接口(如 IEvent),但具体业务事件定义为泛型子类:
-
AddPublishConfigEvent<WordPressConfig>和AddPublishConfigEvent<CnblogsConfig>是两个完全不同的编译期类型 - 每个泛型类内部持有强类型的业务数据字段:
public T Data { get; set; },调用方直接访问e.Data.siteUrl,IDE 自动补全,无强制转换 - 发布时传入具体泛型实例,订阅时也锁定同一泛型类型,二者在编译阶段就完成绑定
订阅与发布都基于泛型参数匹配
订阅方法签名设计为 <TEvent extends IEvent> void subscribe(Consumer<TEvent> handler):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- UI 层写
bus.subscribe(e -> handleWordPressConfig(e)),其中e的类型是AddPublishConfigEvent<WordPressConfig> - Core 层发布
bus.publish(new AddPublishConfigEvent<CnblogsConfig>()),只会触发注册了AddPublishConfigEvent<CnblogsConfig>的监听器 - 不同
T的同名泛型事件互不干扰,不会出现“误通知”或“漏通知”
避免依赖运行时 Class 匹配或字符串路由
传统 EventBus(如 Guava)靠 event.getClass() 查找监听器,容易因继承关系或命名偏差出错:
立即学习“Java免费学习笔记(深入)”;
- 泛型方案不查
Class,也不用String eventType做 key,彻底绕过反射和字符串匹配 - 不支持
Class<? super T>冒泡——这不是缺陷,而是设计取舍:明确要求“谁发谁收”,拒绝隐式向上通知带来的不确定性 - 若需类似“父类事件被多个子类监听”的效果,应显式设计继承结构(如
UserEvent作基类,UserRegisteredEvent和UserUpdatedEvent继承它),再统一订阅UserEvent
配合 Spring 或自研总线落地更稳
泛型机制本身是语言能力,需结合总线实现才能发挥价值:
- Spring 5.2+ 支持泛型事件,可继承
ApplicationEvent并用@EventListener直接监听泛型子类 - 自研内存总线可用
ConcurrentHashMap<Class<?>, List<Consumer<?>>>存储,但注意泛型擦除问题——实际注册时需保留TypeReference或用桥接包装 - 事件对象保持不可变(private final 字段 + public getter),防止监听过程中被意外修改

















