应定义泛型message作为轻量契约层,仅含payload、timestamp、headers,通过静态工厂方法构建不可变实例;producer统一提供send(message)接口,内部适配mq并处理序列化;上下文信息如路由、重试等通过headers传递,避免泛型嵌套或硬编码业务字段。

在消息队列生产者中用泛型统一封装消息体,关键不是给每个消息类写一堆重复代码,而是建立一个轻量、可复用、类型明确的契约层。核心思路是:把“要发什么内容”和“怎么发”解耦,让 Producer 只面向泛型消息接口操作,不关心序列化细节或具体中间件。
定义泛型消息载体 Message
这个类只承载业务数据 + 基础元信息(如 topic、tag、headers),不绑定任何 MQ 实现:
- 泛型参数 T 明确声明业务负载类型,比如
Message<order></order>或Message<paymentevent></paymentevent> - 字段精简:包含
payload: T、timestamp、headers: Map<string string></string>即可,避免塞入 broker 相关字段(如 messageId、retryCount) - 构造私有,提供静态工厂方法:
Message.of(payload)、Message.of(payload, headers),保证不可变性
Producer 接口统一泛型输入
不要为每种消息类型写一个 send 方法。定义一个通用 Producer 接口:
-
<t> SendResult send(Message<t> message)</t></t>—— 所有发送都走这一入口 - 实现类内部负责将
Message<t></t>序列化为字节流(如 JSON 或 Protobuf),并适配目标 MQ(RabbitMQ / RocketMQ / Kafka)的原生 API - 序列化时需传入
Class<t></t>或TypeReference<t></t>,绕过类型擦除,确保反序列化准确
配合消息头(Headers)传递上下文
泛型只管 payload 类型安全,但实际需要传递路由、重试、幂等等控制信息——这些交给 headers:
- 比如设置
headers.put("route-key", "order.created")或"x-retry-count", "2" - Consumer 端可按需读取 headers 做分支处理,不影响泛型 payload 的结构和类型
- 避免把业务字段(如 orderId)硬编码进 Message 泛型类,它不属于“消息体契约”,属于“传输上下文”
避免常见陷阱
泛型封装容易用力过猛,反而增加复杂度:
- 不建议在 Message 中泛型嵌套泛型(如
Message<result>></result>),应在业务层组合,保持 Message 是最薄一层 - 不要让 Message 实现 Serializable —— 序列化策略应由 Producer 决定(JSON 更通用,Kryo 更快),与消息定义解耦
- 不强制要求所有消息继承某个基类,接口 + 泛型 + 不可变对象,已足够清晰
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











