Spring MessageConverter 源码解析:消息转换接口设计与 StringMessageConverter 实现原理
文档教程知识库【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址https://gitcode.com/doocs/source-code-hunter点击查看免费下载导读MessageConverter是 Spring Messaging 抽象层spring-messaging模块中负责消息载荷Payload与 Java 对象双向转换的核心接口也是 JMS、STOMP、WebSocket 等消息技术栈中收发消息与业务对象之间的翻译官。本文基于 doocs/source-code-hunter 仓库中 Spring-MessageConverter.md 的源码笔记逐行剖析MessageConverter接口、AbstractMessageConverter抽象基类与StringMessageConverter的具体实现并结合仓库中配套的 JmsTemplate 与 EnableJms 文档还原消息转换器在真实消息收发链路中的调用位置。读完本文你将能够理解 Spring 消息转换器的 SPI 设计、扩展点以及如何自定义自己的消息转换器。本文分析的源码路径为org.springframework.messaging.converter.MessageConverterSpring Framework 源码对应阅读笔记记录于 docs/Spring/message/Spring-MessageConverter.md。一、MessageConverter消息转换的统一抽象在 Spring Messaging 体系中Message由**载荷payload与消息头MessageHeaders**两部分组成。业务代码通常面向 POJO 编程而底层传输介质JMS 的javax.jms.Message、WebSocket 的文本帧等只能承载字节、字符串等原始形态。MessageConverter正是这一层翻译的抽象接口。public interface MessageConverter { // 从消息转换到 Object解码 Object fromMessage(Message? message, Class? targetClass); // 从 Object 转换到消息编码 Message? toMessage(Object payload, Nullable MessageHeaders headers); }接口只定义了两个方向相反的方法方法方向职责fromMessage(Message? message, Class? targetClass)消息 → 对象将收到的Message载荷按targetClass还原为业务对象toMessage(Object payload, Nullable MessageHeaders headers)对象 → 消息将业务对象payload包装为Message可附带消息头targetClass参数决定解码目标类型headers参数允许编码时携带MessageHeaders如CONTENT_TYPE内容类型头。Spring 框架内置了四个面向不同数据形态的实现类原文档给出了如下清单序号class作用1ByteArrayMessageConverterbyte 数组消息转换器2MappingJackson2MessageConverterjackson2 的消息转换器3MarshallingMessageConverterxml 的消息转换器4StringMessageConverter字符串消息转换器除了这四类直接实现之外从源码笔记附带的类图images/springmessage/image-20200305085013723.png可以看出MessageConverter接口之上还派生出了SmartMessageConverter支持携带conversionHint转换提示的增强接口而AbstractMessageConverter、CompositeMessageConverter组合多个转换器按序尝试等均属于SmartMessageConverter的扩展实现其中AbstractMessageConverter之下又派生出StringMessageConverter、MarshallingMessageConverter、ByteArrayMessageConverter、MappingJackson2MessageConverter等具体转换器。MessageConverter ├── SmartMessageConverter 增强接口支持 conversionHint │ ├── AbstractMessageConverter 抽象基类模板方法 │ │ ├── StringMessageConverter │ │ ├── MarshallingMessageConverter │ │ ├── ByteArrayMessageConverter │ │ └── MappingJackson2MessageConverter │ └── CompositeMessageConverter └── SimpleMessageConverter二、AbstractMessageConverter模板方法封装通用流程直接实现接口需要自行处理是否支持转换、默认 MIME 类型等横切逻辑。AbstractMessageConverter作为抽象基类用模板方法模式把这些通用流程固定下来把差异化的部分留给子类实现。2.1 fromMessage解码流程Override Nullable public final Object fromMessage(Message? message, Class? targetClass) { return fromMessage(message, targetClass, null); } Override Nullable public final Object fromMessage(Message? message, Class? targetClass, Nullable Object conversionHint) { if (!canConvertFrom(message, targetClass)) { return null; } return convertFromInternal(message, targetClass, conversionHint); } // 子类实现 Nullable protected Object convertFromInternal( Message? message, Class? targetClass, Nullable Object conversionHint) { return null; }两个fromMessage方法都被声明为final外部只能通过模板入口调用。执行流程分两步能力检查canConvertFrom(message, targetClass)判断当前转换器是否支持从这种消息、转成这个目标类型不支持则直接返回null注意这里的null语义是无法转换调用方需自行处理真正转换通过convertFromInternal委托给子类该方法在基类中默认返回null由子类覆盖。2.2 toMessage编码流程Override Nullable public final Message? toMessage(Object payload, Nullable MessageHeaders headers) { return toMessage(payload, headers, null); } Override Nullable public final Message? toMessage(Object payload, Nullable MessageHeaders headers, Nullable Object conversionHint) { if (!canConvertTo(payload, headers)) { return null; } // 子类实现 Object payloadToUse convertToInternal(payload, headers, conversionHint); if (payloadToUse null) { return null; } MimeType mimeType getDefaultContentType(payloadToUse); if (headers ! null) { MessageHeaderAccessor accessor MessageHeaderAccessor.getAccessor(headers, MessageHeaderAccessor.class); if (accessor ! null accessor.isMutable()) { if (mimeType ! null) { accessor.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, mimeType); } // 创建信息对象 return MessageBuilder.createMessage(payloadToUse, accessor.getMessageHeaders()); } } MessageBuilder? builder MessageBuilder.withPayload(payloadToUse); if (headers ! null) { builder.copyHeaders(headers); } if (mimeType ! null) { builder.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, mimeType); } return builder.build(); }编码流程比解码多做了三件事值得逐一拆解能力检查canConvertTo(payload, headers)校验载荷类型是否可转换不可转换返回null载荷转换convertToInternal由子类实现把业务对象转换为可传输形态字节数组、字符串等若子类返回null则整体返回null补充内容类型头getDefaultContentType(payloadToUse)依据转换后的载荷推导默认MimeType并写入消息头MessageHeaders.CONTENT_TYPE——这正是消费端能够正确解码的关键元数据消息对象装配这里出现了两条装配路径若传入的headers是可变的MessageHeaderAccessorisMutable()为 true直接复用其消息头并调用MessageBuilder.createMessage(payloadToUse, ...)创建消息否则新建MessageBuilder通过copyHeaders(headers)复制原消息头再build()构建消息对象。2.3 StringMessageConverter最直观的子类示例原文档以StringMessageConverter为范例展示子类如何实现两个模板方法。解码方向convertFromInternalOverride protected Object convertFromInternal(Message? message, Class? targetClass, Nullable Object conversionHint) { Charset charset getContentTypeCharset(getMimeType(message.getHeaders())); Object payload message.getPayload(); return (payload instanceof String ? payload : new String((byte[]) payload, charset)); }逻辑要点从消息头解析出 MIME 类型进而得到对应的字符集CharsetgetContentTypeCharset会依据CONTENT_TYPE头中的charset参数决定若载荷本身就是String则直接返回否则按byte[]以指定字符集解码为字符串——这正对应字符串消息的典型传输形态字节序列 字符集。编码方向convertToInternalOverride Nullable protected Object convertToInternal( Object payload, Nullable MessageHeaders headers, Nullable Object conversionHint) { if (byte[].class getSerializedPayloadClass()) { // 获取编码 Charset charset getContentTypeCharset(getMimeType(headers)); // 获取byte数组 payload ((String) payload).getBytes(charset); } return payload; }逻辑要点getSerializedPayloadClass()决定转换后的载荷以什么类型承载StringMessageConverter的序列化形态通常是byte[]当目标形态为byte[]时将String载荷按解析出的Charset编码为字节数组若序列化形态不是byte[]例如直接以字符串形态传输则原样返回载荷。StringMessageConverter的继承关系可从类图images/springmessage/image-20200305085845017.png中直观看到MessageConverter→SmartMessageConverter→AbstractMessageConverter→StringMessageConverter。三、消息对象装配MessageBuilder 与 ErrorMessage/GenericMessagetoMessage最终都要创建Message实例。原文档剖析了MessageBuilder.createMessage与MessageBuilder.build()两种构建方式的内部逻辑两者结构基本一致。createMessage静态方法SuppressWarnings(unchecked) public static T MessageT createMessage(Nullable T payload, MessageHeaders messageHeaders) { Assert.notNull(payload, Payload must not be null); Assert.notNull(messageHeaders, MessageHeaders must not be null); if (payload instanceof Throwable) { return (MessageT) new ErrorMessage((Throwable) payload, messageHeaders); } else { return new GenericMessage(payload, messageHeaders); } }build()实例方法SuppressWarnings(unchecked) public MessageT build() { if (this.originalMessage ! null !this.headerAccessor.isModified()) { return this.originalMessage; } MessageHeaders headersToUse this.headerAccessor.toMessageHeaders(); if (this.payload instanceof Throwable) { return (MessageT) new ErrorMessage((Throwable) this.payload, headersToUse); } else { return new GenericMessage(this.payload, headersToUse); } }对比两种创建方式可归纳出三点规律异常载荷特判若payload是Throwable异常对象则组装为异常消息ErrorMessage正常载荷否则创建普通的GenericMessage构建优化build()中若消息头未被修改!this.headerAccessor.isModified()且存在原始消息则直接复用原始消息对象避免重复创建。从类图images/springmessage/image-20200305090846313.png可以看到ErrorMessage是GenericMessage的子类二者都实现了Message接口并支持序列化——异常消息与普通消息共享同一套消息抽象只是语义上标记了这是一次异常。四、转换器在真实消息链路中的落点JmsTemplate 视角理解了转换器自身的设计后一个自然的问题是它到底在哪里被调用仓库中配套的 Spring-JmsTemplate.md 给出了 JMS 场景下的答案。JmsTemplate.send发送消息时最终通过MessageCreator.createMessage(session)创建javax.jms.MessageOverride public javax.jms.Message createMessage(Session session) throws JMSException { try { // 消息转换 return this.messageConverter.toMessage(this.message, session); } catch (Exception ex) { throw new MessageConversionException(Could not convert this.message , ex); } }可以看到JmsTemplate内部持有MessageConverter即SimpleMessageConverter或用户自定义转换器发送前调用toMessage把业务对象转换为 JMS 可传输的消息转换失败时抛出MessageConversionException——这正是 2.1 节 中转换器返回null表示不支持这一约定的配套处理机制JmsTemplate.receive接收消息的反向流程doReceive→receiveFromConsumer则对应fromMessage的解码方向。原文档在 JmsTemplate 的分析中注明消息转换后续在更新而本文所解析的 MessageConverter 文档 恰好补齐了这处后续两篇文档相互印证共同构成 JMS 收发消息时业务对象 ↔ 消息完整转换链路的源码视图。五、如何扩展自定义 MessageConverter结合上面的源码分析自定义一个消息转换器的路径非常清晰——继承AbstractMessageConverter只需实现四个钩子方法中的关键两个public class MyMessageConverter extends AbstractMessageConverter { Override protected boolean canConvertFrom(Message? message, Class? targetClass) { // 判断是否支持例如仅处理特定 MIME 类型 / 特定目标类型 return targetClass MyObject.class; } Override protected boolean canConvertTo(Object payload, Nullable MessageHeaders headers) { return payload instanceof MyObject; } Override protected Object convertFromInternal(Message? message, Class? targetClass, Nullable Object conversionHint) { // 解码从消息载荷还原 MyObject // 可借助 getContentTypeCharset(getMimeType(message.getHeaders())) 解析字符集 return ...; } Override protected Object convertToInternal(Object payload, Nullable MessageHeaders headers, Nullable Object conversionHint) { // 编码将 MyObject 转为可传输形态byte[] / String return ...; } }要点回顾只写差异通用流程能力校验、CONTENT_TYPE头填充、MessageBuilder装配由AbstractMessageConverter模板方法统一完成子类无需重复双向成对canConvertFrom/convertFromInternal与canConvertTo/convertToInternal必须成对实现保证能编码就能解码命名即语义MappingJackson2MessageConverterJSON、MarshallingMessageConverterXML、ByteArrayMessageConverter字节数组、StringMessageConverter字符串分别对应一类数据形态选择或扩展时按传输格式对号入座。六、小结本文围绕 Spring Messaging 的MessageConverter抽象完成了从接口到实现的完整源码解读接口层fromMessage消息→对象与toMessage对象→消息构成双向转换的 SPI内置四种数据形态的转换器抽象层AbstractMessageConverter用模板方法固化能力检查 内部转换 内容类型头填充 消息装配的通用流程实现层StringMessageConverter演示了字符集解析与byte[]/String互转的最小实现装配层MessageBuilder区分异常载荷与普通载荷分别产出ErrorMessage与GenericMessage应用层通过 JmsTemplate 的发送链路确认了toMessage的真实调用点转换失败以MessageConversionException暴露给上层。结合仓库的 EnableJms 文档 与 JmsTemplate 文档 可以进一步串联起注解注册监听 → 监听容器创建 → 消息收发 → 消息转换的完整 JMS 消费链路。对消息中间件或 WebSocket 消息场景掌握MessageConverter的设计即可快速定位扩展点实现自定义协议消息与业务对象的无缝互转。赞分享文档教程知识库【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址https://gitcode.com/doocs/source-code-hunter点击查看免费下载相关推荐Spring MessageConverter 消息转换器源码解析从 Message 到 Object 的双向转换机制Spring MessageConverter 消息转换器源码解析从 Message 到 Object 的双向转换机制 导读 本文基于 source code文档教程技术博客知识库JSqlParser源码解析Expression接口设计与实现原理JSqlParser源码解析Expression接口设计与实现原理 引言SQL解析的核心挑战 在现代数据处理系统中SQL语句的解析与处理是核心功能之一。无数据库Apache Spark 源码解析PySpark 与 Spark 之间的消息接口messages 模块实现原理Apache Spark 源码解析PySpark 与 Spark 之间的消息接口messages 模块实现原理 导读 本文以 python/pyspark大数据数据分析批处理流处理机器学习图计算上一篇symfony/psr-http-message-bridge 核心组件解析从工厂类到事件监听器的深度探索下一篇franz-go与Redpanda集成现代事件流平台开发指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

如何在无网络环境用 snapDOM 保存截图:3 级存储与关键参数指南

如何在无网络环境用 snapDOM 保存截图:3 级存储与关键参数指南

如何在无网络环境用 snapDOM 保存截图:3 级存储与关键参数指南 【免费下载链接】snapdom High-performance engine for capturing, modifying, and converting DOM elements into any format. 项目地址: https://gitcode.com/GitHub_Trending/sn/snapdom sna…

2026/9/20 5:17:28 阅读更多 →
SeaTunnel Zeta 引擎监控与指标接入指南:Prometheus 采集、指标体系与 Grafana 可视化实战

SeaTunnel Zeta 引擎监控与指标接入指南:Prometheus 采集、指标体系与 Grafana 可视化实战

数据集成ETL大数据批处理流处理变更数据捕获 【免费下载链接】seatunnel SeaTunnel is a multimodal, high-performance, distributed, massive data integration tool. 项目地址: https://gitcode.com/GitHub_Trending/se/seatunnel 点击查看 免费下载 SeaTunnel …

2026/9/20 5:17:28 阅读更多 →
别再盼着退休了:如何打破职业倦怠,找回对当下的掌控感

别再盼着退休了:如何打破职业倦怠,找回对当下的掌控感

上班让人感到最可怕的地方,是它让我期待变老我明确感知到这件事,是在某个周二的下午。窗外天还大亮,我在工位上翻日历,不是在看假期,而是在算自己离退休还有多少年——二十六,把数字念出来的那一刻&#xf…

2026/9/20 5:16:28 阅读更多 →

最新新闻

郑州seo顾问热狗hotdoger拆解3个实战案例教你搞定网站UI

郑州seo顾问热狗hotdoger拆解3个实战案例教你搞定网站UI

郑州seo顾问热狗hotdoger拆解3个实战案例教你搞定网站UI 不会写代码却想做个像样的官网?这种焦虑我懂。 很多老板或运营负责人,手里攥着预算,脑子里有画面,但对着设计师提的需求,心里直打鼓:这到底合不合理?怎么验收?怎么让网站既能留住人,又能被搜索引擎抓到?…

2026/9/21 6:44:12 阅读更多 →
2026最新wordpress调用字段避坑指南

2026最新wordpress调用字段避坑指南

2026最新wordpress调用字段避坑指南 找建站公司怕被坑高价?这是很多老板和运营新人的心头大患。很多公司报价动辄几万,说得天花乱坠,其实底层技术也就那样。2026最新的数据显示,超过60%的中小企业网站其实可以用更透明的开源方案搞定,比如WordPress。今天咱们不聊虚的,直接拆解Word…

2026/9/21 6:29:22 阅读更多 →
实战案例揭秘:wordpress删除rss的3个关键坑

实战案例揭秘:wordpress删除rss的3个关键坑

实战案例揭秘:wordpress删除rss的3个关键坑 域名解析改错,服务器配置没跟上,导致后台能改前台打不开?这种“域名服务器搞不懂”的噩梦,我在给客户做运维时见过太多次。上个月刚处理的一个 实战案例…

2026/9/21 6:15:47 阅读更多 →
3个实战案例拆解i网站建设报价,拒绝被坑

3个实战案例拆解i网站建设报价,拒绝被坑

3个实战案例拆解i网站建设报价,拒绝被坑 网站做好了没人访问?这不仅是流量焦虑,更是建站前的预算盲区。很多老板拿着“i网站建设”这个模糊的概念去询价,结果被报出从几千到几十万不等的天价,心里直打鼓。…

2026/9/21 6:03:14 阅读更多 →
网站建设的探讨与研究速查手册

网站建设的探讨与研究速查手册

网站建设探讨与研究:5大费用陷阱与选型注意事项 网站做好了没人访问,这是无数甲方老板和运营负责人深夜里最真实的焦虑。钱花出去了,服务器租了,域名买了,甚至SEO优化都上了,结果后台流量曲线平得像心电图停搏。很多人以为技术决定成败,但在我看来, 注意事项 往往比技术本身更决定生死。…

2026/9/21 5:46:06 阅读更多 →
Simulink与FlightGear联合仿真:飞行器控制算法三维可视化验证平台搭建

Simulink与FlightGear联合仿真:飞行器控制算法三维可视化验证平台搭建

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 5:38:52 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →