文章目录
Rabbit MQ和Spring AMQP学习四(JSON消息体)
实际应用场景中,消息的发送和接收大多数情况都是使用Java Object完成的。那么就涉及到两个问题,Producer如何发送Java对象,Consumer如何接收Java对象
Jackson2JsonMessageConverter配置
对于Java对象,Spring AMQP不建议直接使用对象的形式进行传输。建议使用JSON进行传输
JSON更轻量,对于发送和接收两端来说,可以更自由的解析
Producer端配置
@Bean
public Jackson2JsonMessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public RabbitTemplate publishConfirmRabbitTemplate() {
RabbitTemplate result = new RabbitTemplate(publishConnectionFactory());
result.setMessageConverter(messageConverter());
result.setBeforePublishPostProcessors(message -> {
// 设置默认Content-Type
if (message.getMessageProperties().getContentType() == null) {
message.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
}
if (message.getMessageProperties().getTimestamp() == null) {
message.getMessageProperties().setTimestamp(Calendar.getInstance().getTime());
}
return message;
});
......省略其他配置
}
在Producer端直接设置负责发送消息的RabbitTemplate的messageConvert为Jackson.这里RabbitTemplate还设置了setBeforePublishPostProcessors方法,这个方法也是个函数式接口方法,入参为Message对象,在发送前可以加一下自定义操作。比如这里,每条消息发送时都默认带上当前Producer端时间戳
发送消息时,利用jackson将Java对象转为字节进行传输,并设置Content-Type
public void sendDirectPoJoMessage() {
Random random = new Random(100);
SimpleDirectEntity simpleDirectEntity = new SimpleDirectEntity();
simpleDirectEntity.setId(random.nextLong());
simpleDirectEntity.setName("pojo");
simpleDirectEntity.setSimple(true);
Message message = MessageUtils.buildPoJoMessage(simpleDirectEntity);
rabbitTemplate.send(directExchange.getName(), "pojo" , message);
}
public class MessageUtils {
/**
* 消息体为字符串的消息构建.
* @param messageStr 消息字符串
* @param contentType contentType
* @return org.springframework.amqp.core.Message Message对象
*/
public static Message buildStringMessage(String messageStr, String contentType) {
MessageProperties messageProperties = MessagePropertiesBuilder.newInstance().setContentType(contentType).build();
return new Message(messageStr.getBytes(), messageProperties);
}
/**
* 消息体为POJO的消息构建
* @param messagePoJo
* @param <T>
* @return org.springframework.amqp.core.Message Message对象
*/
@SneakyThrows
public static <T> Message buildPoJoMessage(T messagePoJo) {
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes = objectMapper.writeValueAsBytes(messagePoJo);
return MessageBuilder.withBody(bytes).setContentType(MessageProperties.CONTENT_TYPE_JSON).build();
}
}
直接使用Jackson对象转字节方法,并设置ContentType为application/json.
Consumer端配置
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory result = new SimpleRabbitListenerContainerFactory();
result.setConnectionFactory(connectionFactory());
result.setPrefetchCount(2);
result.setMessageConverter(new Jackson2JsonMessageConverter());
return result;
}
这里为什么在SimpleRabbitListenerContainerFactory中配置呢?前面文章分析过,每个@RabbitListener都有一个SimpleMessageListenerContainer,这个实例就是由SimpleRabbitListenerContainerFactory.createContainerInstance方法创建的,
也就是在创建每个Container实例时,设置当前Container的MessageConvert为Jackson的MessageConvter
Consumer端接收JSON
Producer端发送的数据为JSON字符串,Consumer端接收的时候如何自动转为对应的Java实体呢?
Spring AMQP提供了@Payload
@RabbitListener(queues = "${queue.direct.pojo}" )
@RabbitHandler
public void receiveSimplePoJoQueueMessage(@Payload SimpleDirectEntity simpleDirectEntity) {
log.info("接收到的POJO为:{}", simpleDirectEntity);
}
这样我们就可以不用读取Message.body的字节,转为JSON字符串,再转为Java对象了。这些工作都由@Payload注解帮我们完成