资讯动态

Spring MessageConverter 源码解析:消息转换接口设计与 StringMessageConverter 实现原理

发布时间:2026/9/20 5:17:33 来源:尧图企业网站定制
文档教程知识库【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价