RabbitMQ:Jackson2JsonMessageConverter分析
跳到导航
跳到搜索
关于
在看《Spring 实战》:发送异步消息一节,对于 RabbitMQ(RabbitTemplate)提到基于 JSON 的转换,可以使用 Jackson2JsonMessageConverter 作为消息转换器,但是没有提到“在生产者、消费者之间如何实现对象映射”。 虽然可以想到和 JMS(JmsTemplate)基于 JSON 转换所用到的 MappinJackson2MessageConverter 类似:在生产者、消费者端配置消息转换器时,都设置 typeIdPropertyName、typeIdMappins[其他 1]。 但是对于其流程并不十分清楚,所以通过源代码追踪简单分析如下。
执行过程
以下以 RabbitTemplate.convertAndSend(Object object) 为例。
- RabbitTemplate.convertAndSend:
public class RabbitTemplate extends ... { ... // 如果不配置,则默认的 MessageConverter 为 SimpleMessageConverter private MessageConverter messageConverter = new SimpleMessageConverter(); ... ... // setter:setMessageConverter // getter:getMessageConverter ... ... @Override public void convertAndSend(Object object) throws AmqpException { // 使用默认的 exchange、routingKey,而 CorrelationData 为空 convertAndSend(this.exchange, this.routingKey, object, (CorrelationData) null); } @Override public void convertAndSend(String exchange, String routingKey, final Object object, @Nullable CorrelationData correlationData) throws AmqpException { // send 方法发送的信息为 Message 类型,所以需要 convertMessageIfNecessary(object) send(exchange, routingKey, convertMessageIfNecessary(object), correlationData); } @Override public void send(final String exchange, final String routingKey, final Message message, @Nullable final CorrelationData correlationData) throws AmqpException { execute(channel -> { doSend(channel, exchange, routingKey, message, (RabbitTemplate.this.returnsCallback != null || (correlationData != null && StringUtils.hasText(correlationData.getId()))) && isMandatoryFor(message), correlationData); return null; }, obtainTargetConnectionFactory(this.sendConnectionFactorySelectorExpression, message)); } ... // 消息转换:Object -> Message protected Message convertMessageIfNecessary(final Object object) { if (object instanceof Message) { return (Message) object; } /** * 获取“消息转换器”并调用其 toMessage 方法 * 如果使用【Jackson2JsonMessageConverter】,则实际调用【AbstractMessageConverter.toMessage】 * * (Jackson2JsonMessageConverter 只包含构造方法,AbstractMessageConverter 是其父类的父类) */ return getRequiredMessageConverter().toMessage(object, new MessageProperties()); } ... private MessageConverter getRequiredMessageConverter() throws IllegalStateException { MessageConverter converter = getMessageConverter(); // 获取配置的 MessageConverter if (converter == null) { throw new AmqpIllegalStateException( "No 'messageConverter' specified. Check configuration of RabbitTemplate."); } return converter; } }
- 使用“消息转换器”:Jackson2JsonMessageConverter[相关 1] 需要配置(见:RabbitMQ:Jackson2JsonMessageConverter分析#应用配置)。
- 默认“消息转换器”:SimpleMessageConverter[其他 2]。
- AbstractMessageConverter.toMessage:
public abstract class AbstractMessageConverter implements MessageConverter { ... @Override public final Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { // 转换消息,genericType 为空(但此类的 genericType 并无作用) return toMessage(object, messageProperties, null); } @Override public final Message toMessage(Object object, @Nullable MessageProperties messagePropertiesArg, @Nullable Type genericType) throws MessageConversionException { MessageProperties messageProperties = messagePropertiesArg; if (messageProperties == null) { messageProperties = new MessageProperties(); } // 调用 createMessage 方法创建 Message 对象(实际的消息) Message message = createMessage(object, messageProperties, genericType); messageProperties = message.getMessageProperties(); // 保证 Message 的 messageProperties 中 MessageId 不为空 if (this.createMessageIds && messageProperties.getMessageId() == null) { messageProperties.setMessageId(UUID.randomUUID().toString()); } return message; } protected Message createMessage(Object object, MessageProperties messageProperties, @Nullable Type genericType) { return createMessage(object, messageProperties); // 可以看到 genericType 被抛弃了 } /** * 抽象方法,将会在子类中实现: * 如果实用【Jackson2JsonMessageConverter】,则实际调用【AbstractJackson2MessageConverter.createMessage】 */ protected abstract Message createMessage(Object object, MessageProperties messageProperties); }
- MessageProperties[相关 2] 用于保存消息的属性信息。
- AbstractJackson2MessageConverter.createMessage:
public abstract class AbstractJackson2MessageConverter extends AbstractMessageConverter implements BeanClassLoaderAware, SmartMessageConverter { ... public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; protected final ObjectMapper objectMapper; private MimeType supportedContentType; private String supportedCTCharset; @Nullable private ClassMapper classMapper = null; // !!! private Charset defaultCharset = DEFAULT_CHARSET; ... private Jackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); // !!! ... private boolean charsetIsUtf8 = true; ... // 构造方法(以下以 Jackson2JsonMessageConverter 的无参构造为例) protected AbstractJackson2MessageConverter(ObjectMapper objectMapper, MimeType contentType, String... trustedPackages) { Assert.notNull(objectMapper, "'objectMapper' must not be null"); Assert.notNull(contentType, "'contentType' must not be null"); this.objectMapper = objectMapper; // 为 new ObjectMapper()的对象 this.supportedContentType = contentType; // 为 "application/json" 的 MimeType(MIME 类型) this.supportedCTCharset = this.supportedContentType.getParameter("charset"); ((DefaultJackson2JavaTypeMapper) this.javaTypeMapper).setTrustedPackages(trustedPackages); } ... @Override protected Message createMessage(Object objectToConvert, MessageProperties messageProperties) throws MessageConversionException { // 创建 Message 对象,genericType 为空 return createMessage(objectToConvert, messageProperties, null); } @Override protected Message createMessage(Object objectToConvert, MessageProperties messageProperties, @Nullable Type genericType) throws MessageConversionException { byte[] bytes; // 通过 objectMapper 将 objectToConvert(要发送的对象)转换为 byte[] try { // 默认:以 Utf8(JsonEncoding.UTF8) 转换对象 if (this.charsetIsUtf8 && this.supportedCTCharset == null) { bytes = this.objectMapper.writeValueAsBytes(objectToConvert); } // 以设置的 supportedCTCharset 转换对象 else { String jsonString = this.objectMapper .writeValueAsString(objectToConvert); String encoding = this.supportedCTCharset != null ? this.supportedCTCharset : getDefaultCharset(); bytes = jsonString.getBytes(encoding); } } catch (IOException e) { throw new MessageConversionException("Failed to convert Message content", e); } /** * messageProperties:设置内容的 MIME 类型 * * supportedContentType由“构造方法、set方法”指定,默认:"application/json" */ messageProperties.setContentType(this.supportedContentType.toString()); /** * messageProperties:设置内容的字符集 * * supportedCTCharset由“构造方法、set方法”指定,默认:StandardCharsets.UTF_8 */ if (this.supportedCTCharset == null) { messageProperties.setContentEncoding(getDefaultCharset()); } // messageProperties:设置内容的长度 messageProperties.setContentLength(bytes.length); /** * messageProperties:【设置对象类型!!!】 * * 1、classMapper:只能由“set方法”指定,默认:空 * * 2、javaTypeMapper:只能由“set方法”指定,默认已设置为:DefaultJackson2JavaTypeMapper */ if (getClassMapper() == null) { //【通过 objectMapper 构建 JavaType 对象】 JavaType type = this.objectMapper.constructType( genericType == null ? objectToConvert.getClass() : genericType); if (genericType != null && !type.isContainerType() && Modifier.isAbstract(type.getRawClass().getModifiers())) { type = this.objectMapper.constructType(objectToConvert.getClass()); } /** * 通过 javaTypeMapper 的配置(Jackson2JavaTypeMapper 的实现类), * 将 JavaType 设置到 messageProperties * * 【默认将调用 DefaultJackson2JavaTypeMapper.fromJavaType】 */ getJavaTypeMapper().fromJavaType(type, messageProperties); } else { /** * 通过 classMapper 的配置(ClassMapper 的实现类), * 将 objectToConvert.getClass() 设置到 messageProperties */ getClassMapper().fromClass(objectToConvert.getClass(), messageProperties); // NOSONAR never null } return new Message(bytes, messageProperties); } }
- DefaultJackson2JavaTypeMapper[相关 6].fromJavaType:
public class DefaultJackson2JavaTypeMapper extends AbstractJavaTypeMapper implements Jackson2JavaTypeMapper { ... /** * 以下 addHeader、getClassIdFieldName、getContentClassIdFieldName、getKeyClassIdFieldName 方法 * 均已在父类 AbstractJavaTypeMapper 中实现 */ @Override public void fromJavaType(JavaType javaType, MessageProperties properties) { /** * 向 messageProperties 的【“__TypeId__”】中写入 javaType 的“原始类型”【即,对象本身的类型】 */ addHeader(properties, getClassIdFieldName(), javaType.getRawClass()); /** * 如果 javaType 表示的类型是“数组类型”以外的“容器类型”,【即,对象是一个容器类型】 * 向 messageProperties 的【“__ContentTypeId__”】中写入 javaType 元素的类型【即,对象的元素的类型】 * * P.S. “容器类型”:包括数组、映射和集合类型 */ if (javaType.isContainerType() && !javaType.isArrayType()) { addHeader(properties, getContentClassIdFieldName(), javaType.getContentType().getRawClass()); } /** * 如果 javaType 的 _keyType 不为空,【即,对象是一个映射类型】 * 向 messageProperties 的【“__KeyTypeId__”】中写入 javaType 的 _keyType 的类型【即,对象的 key 的类型】 * * P.S. _keyType 用于表示 MapLikeType(表示一个 Map-like 的类型)的“键的类型” */ if (javaType.getKeyType() != null) { addHeader(properties, getKeyClassIdFieldName(), javaType.getKeyType().getRawClass()); } } ... }
- AbstractJavaTypeMapper.addHeader:
public abstract class AbstractJavaTypeMapper implements BeanClassLoaderAware { ... // 用于保存 JavaType 的“原始类型” public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__"; // 用于保存 JavaType 的“元素的类型” public static final String DEFAULT_CONTENT_CLASSID_FIELD_NAME = "__ContentTypeId__"; // 用于保存 JavaType 的“key 的类型” public static final String DEFAULT_KEY_CLASSID_FIELD_NAME = "__KeyTypeId__"; // 用于保存 String -> Class<?> 的映射 private final Map<String, Class<?>> idClassMapping = new HashMap<String, Class<?>>(); // 用于保存 Class<?> -> String 的映射:由 idClassMapping 的键值反转得到 private final Map<Class<?>, String> classIdMapping = new HashMap<Class<?>, String>(); ... public String getClassIdFieldName() { return DEFAULT_CLASSID_FIELD_NAME; } public String getContentClassIdFieldName() { return DEFAULT_CONTENT_CLASSID_FIELD_NAME; } public String getKeyClassIdFieldName() { return DEFAULT_KEY_CLASSID_FIELD_NAME; } // 设置 idClassMapping: public void setIdClassMapping(Map<String, Class<?>> idClassMapping) { this.idClassMapping.putAll(idClassMapping); createReverseMap(); } // 设置 classIdMapping:将 idClassMapping 的键值反转 private void createReverseMap() { this.classIdMapping.clear(); for (Map.Entry<String, Class<?>> entry : this.idClassMapping.entrySet()) { String id = entry.getKey(); Class<?> clazz = entry.getValue(); this.classIdMapping.put(clazz, id); } } ... protected void addHeader(MessageProperties properties, String headerName, Class<?> clazz) { /** * 向 MessageProperties.headers 中添加(“要发送对象的”)类型: * * 1、如果 classIdMapping 中存在 String -> Class<?> 的映射,则写入对应的 String * * 2、否则,写入 Class<?> 的名称 */ if (this.classIdMapping.containsKey(clazz)) { properties.getHeaders().put(headerName, this.classIdMapping.get(clazz)); } else { properties.getHeaders().put(headerName, clazz.getName()); } } }
相关
- ↑
Jackson2JsonMessageConverter 的类层次:
Jackson2JsonMessageConverter extends AbstractJackson2MessageConverter AbstractJackson2MessageConverter extends AbstractMessageConverter implements BeanClassLoaderAware, SmartMessageConverter AbstractMessageConverter implements MessageConverter
- Jackson2JsonMessageConverter:【类】只有构造方法,其他实用方法都在父类实现。
- 构造方法:用于指定 objectMapper、supportedContentType 等
- AbstractJackson2MessageConverter:【抽象类】但包括了几乎所有属性和方法。 —— 【核心】
- 属性:
- ClassMapper / Jackson2JavaTypeMapper:用于向 MessageProperties.headers 中写入“__TypeId__”等字段;
- 方法:(都已实现)
- createMessage:用于“Object -> Message”转换
- fromMessage:用于“Message -> Object”转换
- 属性:
- AbstractMessageConverter:【抽象类】只包括了部分方法(“Object -> Message”),其余在子类实现。
- 方法:
- toMessage:用于“Object -> Message”转换,将调用 createMessage 方法
- createMessage:(调用子类的 createMessage 方法)
- SimpleMessageConverter也间接继承了该抽象类。 ——【RabbitTemplate 默认的 MessageConverter】
- 方法:
- MessageConverter:【接口】消息转换器接口。
public interface MessageConverter { // Convert a Java object to a Message. Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException; default Message toMessage(Object object, MessageProperties messageProperties, @Nullable Type genericType) throws MessageConversionException { return toMessage(object, messageProperties); } // Convert from a Message to a Java object. Object fromMessage(Message message) throws MessageConversionException; }
public class Jackson2JsonMessageConverter extends AbstractJackson2MessageConverter { // 1、无参构造 public Jackson2JsonMessageConverter() { // 将调用 2、含参(trustedPackages)构造,并指定了 trustedPackages 为 "*" this("*"); } // 2、含参(trustedPackages)构造 public Jackson2JsonMessageConverter(String... trustedPackages) { // 将调用 4、含参(trustedPackages、trustedPackages)构造,并指定了 ObjectMapper 为 ObjectMapper 对象 this(new ObjectMapper(), trustedPackages); this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } // 3、含参(ObjectMapper)构造 public Jackson2JsonMessageConverter(ObjectMapper jsonObjectMapper) { // 将调用 4、含参(trustedPackages、trustedPackages)构造,并指定了 trustedPackages 为 "*" this(jsonObjectMapper, "*"); } // 4、含参(trustedPackages、trustedPackages)构造 public Jackson2JsonMessageConverter(ObjectMapper jsonObjectMapper, String... trustedPackages) { // 将调用父类(AbstractJackson2MessageConverter)的构造方法 // 并指定了父类的 supportedContentType 属性 ————(MessageProperties.CONTENT_TYPE_JSON 为 【"application/json"】) super(jsonObjectMapper, MimeTypeUtils.parseMimeType(MessageProperties.CONTENT_TYPE_JSON), trustedPackages); } }
- 如上,使用无参构造时:
- objectMapper 为 ObjectMapper 实例
- MimeType 为 "application/json"
- ↑ 2.0 2.1
MessageProperties:用于保存消息的各项属性
public class MessageProperties implements Serializable { ... public static final String CONTENT_TYPE_JSON = "application/json"; ... private final Map<String, Object> headers = new HashMap<>(); // 以 Map 保存的头信息 ... private String messageId; ... public Map<String, Object> getHeaders() { return this.headers; } ... }
- MessageProperties 是 Message 类的属性(二者都位于:“org.springframework.amqp.core”)。
- ↑
ObjectMapper:用于快速的进行各个类型和Json类型的相互转换。
ObjectMapper 提供了用于读取和写入 JSON 的功能,无论是从基本的 POJO(普通的旧 Java 对象)还是从通用的 JSON 树模型({@link JsonNode})读取和写入JSON,以及用于执行转换的相关功能。
- 位于:“com.fasterxml.jackson.databind”
- 参考:【Java ObjectMapper详解】
- ↑
JavaType:类型标记类的基类,用于包含信息和用作反序列化程序的键。
package com.fasterxml.jackson.databind; import ... public abstract class JavaType extends ResolvedType implements java.io.Serializable, // 2.1 java.lang.reflect.Type // 2.2 {
- 父类:java.lang.reflect.Type ——(参考:【Type接口:Java中的类型】)
- 子类:(“TypeBase”:
TypeBase extends JavaType implements JsonSerializable
)
Class Parent Description SimpleType TypeBase 简单类型:定义为除已识别的容器类型(数组、集合、映射)之外的任何类型 - 自定义的类,对应的都是 SimpleType
ArrayType TypeBase 数组类型表示 Java 数组。 ——包括“基本数组”和“对象值数组” - 此外,对象值数组可以具有任何其他元素类型。
CollectionType CollectionLikeType 表示 Java 集合类型(列表、集)的类型。 CollectionLikeType TypeBase 表示类似于集合类型的事物的类型。 ——不一定实现“{@link java.util.Collection}” - 这特别允许框架检查用于 Map 类型的配置和注释设置,并将其传递给可能更熟悉实际类型的自定义处理程序。
MapType MapLikeType 表示“真正的”Java 映射类型的类型。 MapLikeType TypeBase 表示类似映射类型的事物的类型,由键值对组成。 ——不一定实现“{@link java.util.Map}” - 但没有足够的内省功能来允许某种级别的泛型处理。
- 这特别允许框架检查用于 Map 类型的配置和注释设置,并将其传递给可能更熟悉实际类型的自定义处理程序。
PlaceholderForType TypeBase 侦测已解析类型的绑定时使用的帮助程序类型,这是专用化所必需的。 ResolvedRecursiveType TypeBase 用于自引用的内部占位符类型。 ReferenceType SimpleType 专用 {@link SimpleType},用于引用类型类型,即可以取消引用到不同类型的另一个值(或 null)的值。 - 引用的类型可以使用 {@link getContentType()} 访问。
- ↑
ClassMapper:(接口)用于在消息上设置元数据(MessageProperties),以便可以在接收消息时创建需要实例化的类。
public interface ClassMapper { void fromClass(Class<?> clazz, MessageProperties properties); Class<?> toClass(MessageProperties properties); }
- 子接口:
public interface Jackson2JavaTypeMapper extends ClassMapper {
- 实现类:
public class DefaultClassMapper implements ClassMapper, InitializingBean { public class DefaultJackson2JavaTypeMapper extends AbstractJavaTypeMapper implements Jackson2JavaTypeMapper {
- ↑
DefaultJackson2JavaTypeMapper:
- AbstractJackson2MessageConverter(Jackson2JsonMessageConverter) 默认的 Jackson2JavaTypeMapper(ClassMapper)
public class DefaultJackson2JavaTypeMapper extends AbstractJavaTypeMapper implements Jackson2JavaTypeMapper { ... @Override public void fromJavaType(JavaType javaType, MessageProperties properties) { ... } @Override public JavaType toJavaType(MessageProperties properties) { ... } @Override public void fromClass(Class<?> clazz, MessageProperties properties) { fromJavaType(TypeFactory.defaultInstance().constructType(clazz), properties); } @Override public Class<?> toClass(MessageProperties properties) { return toJavaType(properties).getRawClass(); } }
应用配置[参考 1]
由以上过程可知(使用 Jackson2JsonMessageConverter 时): 1、Jackson2JsonMessageConverter 的构造方法用于指定 objectMapper、supportedContentType(消息的内容类型) 2、Jackson2JsonMessageConverter 的 Jackson2JavaTypeMapper(用于 JavaType 映射)默认为 DefaultJackson2JavaTypeMapper DefaultJackson2JavaTypeMapper 继承与 AbstractJavaTypeMapper(抽象类) AbstractJavaTypeMapper 中: 1、__TypeId__:用于指定 MessageProperties.headers 中保存“要发送对象的类型”的字段名称 2、idClassMapping:用于保存“Class -> String”的映射 MessageProperties.headers(Map<String, Object> 类型)的写入过程: 1、headers 的 key:写入“__TypeId__”; 2、headers 的 value:如果 AbstractJavaTypeMapper.idClassMapping 中有对应的映射,则写入对应 String,否则,写入“要发送对象的类型”的全限定名。
在消息的“生产者”和“消费者”之间传递消息,则必须:
- 依赖相同的 jar;
- 拥有相同(全限定名相同)的类;
- 获取 Message,然后自己解析;
对于“生产者”和“消费者”之间的解耦,必须: 1、配置 Jackson2JsonMessageConverter:设置 DefaultJackson2JavaTypeMapper 的 idClassMapping。 2、配置 Jackson2JsonMessageConverter:使用自定义的 ClassMapper(fromClass、toClass)和 JavaTypeMapper(fromJavaType、toJavaType)。
Jackson2JsonMessageConverter 配置:
- 方案一:设置 DefaultJackson2JavaTypeMapper 的 idClassMapping
- 生产者:
@Configuration public class RabbitConfiguration { @Bean public MessageConverter messageConverter() { Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); // Producer: String -> Class<?> Map<String, Class<?>> idClassMapping = new HashMap<>(); idClassMapping.put("Bean1", producer.Bean1.class); idClassMapping.put("Bean2", producer.Bean2.class); // ... more setting javaTypeMapper.setIdClassMapping(idClassMapping); messageConverter.setJavaTypeMapper(javaTypeMapper); return messageConverter; } ... }
- 消费者:
@Configuration public class RabbitConfiguration { @Bean public MessageConverter messageConverter() { Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); // Consumer: String -> Class<?> Map<String, Class<?>> idClassMapping = new HashMap<>(); idClassMapping.put("Bean1", consumer.Bean1.class); idClassMapping.put("Bean2", consumer.Bean2.class); // ... more setting javaTypeMapper.setIdClassMapping(idClassMapping); messageConverter.setJavaTypeMapper(javaTypeMapper); return messageConverter; } ... }
- 生产者:
- 方案二:使用自定义的 ClassMapper和 JavaTypeMapper
- 生产者:
@Configuration public class RabbitConfiguration { @Bean public MessageConverter messageConverter() { // Producer: Class<?> -> String Map<Class<?>, String> classIdMapping = new HashMap<Class<?>, String>(); classIdMapping.put(producer.Bean1.class, "Bean1"); classIdMapping.put(producer.Bean2.class, "Bean2"); // ... more setting Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); messageConverter.setClassMapper(new ClassMapper() { ... @Override public void fromClass(Class<?> clazz, MessageProperties properties) { // Set "__TypeId__" with classIdMapping properties.setHeader("__TypeId__", classIdMapping.get(clazz)); } }); return messageConverter; } ... }
- 消费者:
@Configuration public class RabbitConfiguration { @Bean public MessageConverter messageConverter() { // Consumer: String -> Class<?> Map<String, Class<?>> idClassMapping = new HashMap<>(); idClassMapping.put("Bean1", consumer.Bean1.class); idClassMapping.put("Bean2", consumer.Bean2.class); // ... more setting Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); messageConverter.setClassMapper(new ClassMapper() { ... @Override public Class<?> toClass(MessageProperties properties) { // Get "__TypeId__" String typeId = (String) properties.getHeaders().get("__TypeId__"); // Get Class<?> with classIdMapping return idClassMapping.get(typeId); } }); return messageConverter; } ... }
- 生产者:
参考&其他
参考
其他
- ↑
JMS 的 MappinJackson2MessageConverter 配置:【分别在“生产者”、“消费者”中配置】
@Configuration public class JmsConfiguration { @Bean public MappingJackson2MessageConverter messageConverter(){ MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter(); // 1、设置: typeIdPropertyName messageConverter.setTypeIdPropertyName("_typeId"); // 添加 Map<String, Class<?>>:用于保存“String -> Class<?>”的映射 Map<String, Class<?>> typeIdMapping = new HashMap<>(); typeIdMapping.put("Bean1", bean1.class); typeIdMapping.put("Bean2", bean2.class); // 2、设置:typeIdMapping messageConverter.setTypeIdMappings(typeIdMapping); return messageConverter; } ... }
- 在“生产者”、“消费者”间传递消息时,会通过 Message.setStringProperty(String name, String value) 方法设置对象的类型,其中:
- name:为 “typeIdPropertyName 属性”的值,
- value:为(通过“classIdMappings 属性”映射的)表示对象类型的 String 值。
- MappingJackson2MessageConverter 类:
- 属性:
- typeIdPropertyName:保存“Message 中表示对象类型的字段的名称”; —— 没有默认值,必须设置
- idClassMappings:保存“String -> Class<?>”的映射;
- classIdMappings:保存“Class<?> -> String”的映射;
- 方法:
- setTypeIdPropertyName(...):用于设置 typeIdPropertyName 属性;
- setTypeIdMappings(...):用于设置 idClassMappings 和 classIdMappings 属性;
- toMessage(...):用于“Object -> Message”转换,需要 classIdMappings 属性;
- fromMessage(...):用于“Message -> Object”转换,需要 idClassMappings 属性;
- 该类位于“org.springframework.jms.support.converter”包(区别于“org.springframework.messaging.converter”包下的同名类)。
- 属性:
- ↑
SimpleMessageConverter:【RabbitTemplate 默认的 MessageConverter】
public class SimpleMessageConverter extends AllowedListDeserializingMessageConverter implements BeanClassLoaderAware { public static final String DEFAULT_CHARSET = "UTF-8"; private volatile String defaultCharset = DEFAULT_CHARSET; ... public void setDefaultCharset(String defaultCharset) { this.defaultCharset = (defaultCharset != null) ? defaultCharset : DEFAULT_CHARSET; } ... /** * 由给定的 Object 创建 AMQP Message。 * * 如下,支持的载荷为:byte[]、String、Serializable */ @Override protected Message createMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { byte[] bytes = null; /** * 转换消息载荷(仅支持:byte[]、String、Serializable) */ if (object instanceof byte[]) { bytes = (byte[]) object; // messageProperties:设置内容的 MIME 类型为 "application/octet-stream" messageProperties.setContentType(MessageProperties.CONTENT_TYPE_BYTES); } else if (object instanceof String) { try { bytes = ((String) object).getBytes(this.defaultCharset); } catch (UnsupportedEncodingException e) { throw new MessageConversionException( "failed to convert to Message content", e); } // messageProperties:设置内容的 MIME 类型为 "text/plain" messageProperties.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN); /// messageProperties:设置内容的字符集(由“set方法”指定,默认为:"UTF-8") messageProperties.setContentEncoding(this.defaultCharset); } else if (object instanceof Serializable) { try { bytes = SerializationUtils.serialize(object); } catch (IllegalArgumentException e) { throw new MessageConversionException( "failed to convert to serialized Message content", e); } // messageProperties:设置内容的 MIME 类型为 "application/x-java-serialized-object" messageProperties.setContentType(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT); } /** * 生成 AMQP Message 并返回 */ if (bytes != null) { // messageProperties:设置内容的长度 messageProperties.setContentLength(bytes.length); return new Message(bytes, messageProperties); } throw new IllegalArgumentException(getClass().getSimpleName() + " only supports String, byte[] and Serializable payloads, received: " + object.getClass().getName()); } @Override public Object fromMessage(Message message) throws MessageConversionException { ... } ... }
- 相同:都(间接)继承于“AbstractMessageConverter”。
- 不同:
- 不能在“生产者”、“消费者”间传递对象的类型。
- ——因为没有“ClassMapper”/“Jackson2JavaTypeMapper”属性,所以不会向 MessageProperties.headers 中写入“__TypeId__”等字段。
- 只支持:byte[]、String、Serializable 类型的消息载荷。
- 不能在“生产者”、“消费者”间传递对象的类型。