RabbitMQ:Jackson2JsonMessageConverter分析

来自Wikioe
跳到导航 跳到搜索


关于

在看《Spring 实战》:发送异步消息一节,对于 RabbitMQ(RabbitTemplate)提到基于 JSON 的转换,可以使用 Jackson2JsonMessageConverter 作为消息转换器,但是没有提到“在生产者、消费者之间如何实现对象映射”。

虽然可以想到和 JMS(JmsTemplate)基于 JSON 转换所用到的 MappinJackson2MessageConverter 类似:在生产者、消费者端配置消息转换器时,都设置 typeIdPropertyName、typeIdMappins[其他 1]。

但是对于其流程并不十分清楚,所以通过源代码追踪简单分析如下。

执行过程

以下以 RabbitTemplate.convertAndSend(Object object) 为例。
  1. 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;
    	}
    }
    
  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] 用于保存消息的属性信息。
  3. 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);
    	}
    }
    
    • AbstractJackson2MessageConverter 包含了“ObjectMapper”和“ClassMapper”类型的属性。
      1. ObjectMapper[相关 3]:用于生成“JavaType[相关 4] 的对象”(用于表示“要发送对象的类型”)。
      2. ClassMapper[相关 5]:用于向 MessageProperties [相关 2] 添加“要发送对象的类型”。
  4. 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());
    		}
    	}
    	...
    }
    
  5. 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());
    		}
    	}
    }
    

相关

  1. Jackson2JsonMessageConverter 的类层次:
    Jackson2JsonMessageConverter extends AbstractJackson2MessageConverter
    
    AbstractJackson2MessageConverter extends AbstractMessageConverter implements BeanClassLoaderAware, SmartMessageConverter
    
    AbstractMessageConverter implements MessageConverter
    
    1. Jackson2JsonMessageConverter:【类】只有构造方法,其他实用方法都在父类实现。
      • 构造方法:用于指定 objectMapper、supportedContentType 等
    2. AbstractJackson2MessageConverter:【抽象类】但包括了几乎所有属性和方法。 —— 【核心】
      • 属性:
        ClassMapper / Jackson2JavaTypeMapper:用于向 MessageProperties.headers 中写入“__TypeId__”等字段;
      • 方法:(都已实现)
        createMessage:用于“Object -> Message”转换
        fromMessage:用于“Message -> Object”转换
    3. AbstractMessageConverter:【抽象类】只包括了部分方法(“Object -> Message”),其余在子类实现。
      • 方法:
        toMessage:用于“Object -> Message”转换,将调用 createMessage 方法
        createMessage:(调用子类的 createMessage 方法)
      • SimpleMessageConverter也间接继承了该抽象类。 ——【RabbitTemplate 默认的 MessageConverter】
    4. 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;
      }
      
    Jackson2JsonMessageConverter 类:只有构造方法(用于指定 ObjectMapper 等)
    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. 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”)。
  3. ObjectMapper用于快速的进行各个类型和Json类型的相互转换。

    ObjectMapper 提供了用于读取和写入 JSON 的功能,无论是从基本的 POJO(普通的旧 Java 对象)还是从通用的 JSON 树模型({@link JsonNode})读取和写入JSON,以及用于执行转换的相关功能。

  4. 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()} 访问。
  5. 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 {
      
  6. 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,否则,写入“要发送对象的类型”的全限定名

在消息的“生产者”和“消费者”之间传递消息,则必须:

  1. 依赖相同的 jar;
  2. 拥有相同(全限定名相同)的类;
  3. 获取 Message,然后自己解析;
对于“生产者”和“消费者”之间的解耦,必须:

1、配置 Jackson2JsonMessageConverter:设置 DefaultJackson2JavaTypeMapperidClassMapping。

2、配置 Jackson2JsonMessageConverter:使用自定义的 ClassMapper(fromClass、toClass)和 JavaTypeMapper(fromJavaType、toJavaType)。

Jackson2JsonMessageConverter 配置:

  1. 方案一:设置 DefaultJackson2JavaTypeMapperidClassMapping
    1. 生产者:
      @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;
      	}
      	...
      }
      
    2. 消费者:
      @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;
      	}
      	...
      }
      
  2. 方案二:使用自定义的 ClassMapperJavaTypeMapper
    1. 生产者:
      @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;
      	}
      	...
      }
      
    2. 消费者:
      @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;
      	}
      	...
      }
      

参考&其他

参考

其他

  1. JMSMappinJackson2MessageConverter 配置:【分别在“生产者”、“消费者”中配置】
    @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) 方法设置对象的类型,其中:
      1. name:为 “typeIdPropertyName 属性”的值,
      2. value:为(通过“classIdMappings 属性”映射的)表示对象类型的 String 值。
    • MappingJackson2MessageConverter 类:
      • 属性:
        1. typeIdPropertyName:保存“Message 中表示对象类型的字段的名称”; —— 没有默认值,必须设置
        2. idClassMappings:保存“String -> Class<?>”的映射;
        3. classIdMappings:保存“Class<?> -> String”的映射;
      • 方法:
        1. setTypeIdPropertyName(...):用于设置 typeIdPropertyName 属性;
        2. setTypeIdMappings(...):用于设置 idClassMappings 和 classIdMappings 属性;
        3. toMessage(...):用于“Object -> Message”转换,需要 classIdMappings 属性;
        4. fromMessage(...):用于“Message -> Object”转换,需要 idClassMappings 属性;
      • 该类位于“org.springframework.jms.support.converter”包(区别于“org.springframework.messaging.converter”包下的同名类)。
  2. 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 {
    		...
    	}
    	
    	...
    }
    
    SimpleMessageConverter”与“Jackson2JsonMessageConverter”(AbstractJackson2MessageConverter)区别:
    • 相同:都(间接)继承于“AbstractMessageConverter”。
    • 不同:
      1. 不能在“生产者”、“消费者”间传递对象的类型
        ——因为没有“ClassMapper”/“Jackson2JavaTypeMapper”属性,所以不会向 MessageProperties.headers 中写入“__TypeId__”等字段。
      2. 只支持:byte[]、String、Serializable 类型的消息载荷