本博客属于 《RabbitMQ基础组件封装—整体结构》的子博客
一、自定义的Object对象和Spring中的Object对象
1. 首先自定义一个Object类,Message.java:
public class Message implements Serializable {
private static final long serialVersionUID = 841277940410721237L;
/* 消息的唯一ID */
private String messageId;
/* 消息的主题 */
private String topic;
/* 消息的路由规则 */
private String routingKey = "";
/* 消息的附加属性 */
private Map<String, Object> attributes = new HashMap<String, Object>();
/* 延迟消息的参数配置 */
private int delayMills;
/* 消息类型:默认为confirm消息类型 */
private String messageType = MessageType.CONFIRM;
public Message() {
}
public Message(String messageId, String topic, String routingKey, Map<String, Object> attributes, int delayMills) {
this.messageId = messageId;
this.topic = topic;
this.routingKey = routingKey;
this.attributes = attributes;
this.delayMills = delayMills;
}
public Message(String messageId, String topic, String routingKey, Map<String, Object> attributes, int delayMills,
String messageType) {
this.messageId = messageId;
this.topic = topic;
this.routingKey = routingKey;
this.attributes = attributes;
this.delayMills = delayMills;
this.messageType = messageType;
}
// getter、setter方法省略
}
2. Spring中的Object类为 org.springframework.amqp.core.Message
3. 结构
这里封装的内容是自定义的Message和org.springframework.amqp.core.Message之间的转换。
其中包括两个关键过程:
(1)将我们自己的Message对象序列化为byte[],作为org.springframework.amqp.core.Message类的body属性值。
(2)将 org.springframework.amqp.core.Message 类中的body(一个byte[]类型)反序列化为我们自己的Message对象。
二、实现序列化方法
1. 编写一个创建序列化对象的入口:
public interface SerializerFactory {
# 这个 Serializer 需要自己定义
Serializer create();
}
2. 自定义一个序列化对象 Serializer.java
/**
* 序列化和反序列化的接口
*/
public interface Serializer {
byte[] serializeRaw(Object data);
String serialize(Object data);
<T> T deserialize(String content);
<T> T deserialize(byte[] content);
}
3. Serializer.java的实现类 JacksonSerializer.java
public class JacksonSerializer implements Serializer {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonSerializer.class);
private static final ObjectMapper mapper = new ObjectMapper();
static {
// 一些必要的非空性、错误性约束
mapper.disable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
mapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
}
private final JavaType type;
private JacksonSerializer(JavaType type) {
this.type = type;
}
public JacksonSerializer(Type type) {
this.type = mapper.getTypeFactory().constructType(type);
}
public static JacksonSerializer createParametricType(Class<?> cls) {
return new JacksonSerializer(mapper.getTypeFactory().constructType(cls));
}
public byte[] serializeRaw(Object data) {
try {
return mapper.writeValueAsBytes(data);
} catch (JsonProcessingException e) {
LOGGER.error("序列化出错", e);
}
return null;
}
public String serialize(Object data) {
try {
return mapper.writeValueAsString(data);
} catch (JsonProcessingException e) {
LOGGER.error("序列化出错", e);
}
return null;
}
public <T> T deserialize(String content) {
try {
return mapper.readValue(content, type);
} catch (IOException e) {
LOGGER.error("反序列化出错", e);
}
return null;
}
public <T> T deserialize(byte[] content) {
try {
return mapper.readValue(content, type);
} catch (IOException e) {
LOGGER.error("反序列化出错", e);
}
return null;
}
}
4. 根据上面第 3 步的代码,去对第 1 步的 SerializerFactory.java 进行实现:JacksonSerializerFactory.java
public class JacksonSerializerFactory implements SerializerFactory{
// 定义一个单例模式的对象
public static final SerializerFactory INSTANCE = new JacksonSerializerFactory();
@Override
public Serializer create() {
// 传入 Message.class ,则在反序列化时都会转成这个 Message.class
return JacksonSerializer.createParametricType(Message.class);
}
}
三、实现自定义 Message 和 org.springframework.amqp.core.Message 之间的转换
1. 实现转换方法 GenericMessageConverter.java
public class GenericMessageConverter implements MessageConverter {
private Serializer serializer;
/**
* 构造方法
*/
public GenericMessageConverter(Serializer serializer) {
Preconditions.checkNotNull(serializer);
this.serializer = serializer;
}
/**
* 将 org.springframework.amqp.core.Message 中的 body 属性反序列化成自定义的 Message
* 该方法用于从 RabbitMQ服务中接收消息时,转成我们自己定义的Message对象
*/
@Override
public Object fromMessage(org.springframework.amqp.core.Message message) throws MessageConversionException {
return this.serializer.deserialize(message.getBody());
}
/**
* 将 自定义的 Message 序列化之后作为 body 属性赋值给 org.springframework.amqp.core.Message
* 该方法用于将消息发送到 RabbitMQ服务中时,转成 RabbitMQ 可以接收的类型
*/
@Override
public org.springframework.amqp.core.Message toMessage(Object object, MessageProperties messageProperties)
throws MessageConversionException {
return new org.springframework.amqp.core.Message(this.serializer.serializeRaw(object), messageProperties);
}
}
2. 使用装饰者模式,对原来的 GenericMessageConverter.java 进行包装,增加一些额外的逻辑,RabbitMessageConverter.java
public class RabbitMessageConverter implements MessageConverter {
private GenericMessageConverter delegate;
private final String delaultExprie = String.valueOf(24 * 60 * 60 * 1000);
public RabbitMessageConverter(GenericMessageConverter genericMessageConverter) {
Preconditions.checkNotNull(genericMessageConverter);
this.delegate = genericMessageConverter;
}
@Override
public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
messageProperties.setExpiration(delaultExprie);
// com.bfxy.rabbit.api.Message message = (com.bfxy.rabbit.api.Message)object;
// messageProperties.setDelay(message.getDelayMills());
return this.delegate.toMessage(object, messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
com.bfxy.rabbit.api.Message msg = (com.bfxy.rabbit.api.Message) this.delegate.fromMessage(message);
return msg;
}
}
四、使用
可以将其使用在 RabbitMQ 中的发消息和接收消息的操作中,RabbitTemplateContainer.java
@Slf4j
@Component
public class RabbitTemplateContainer implements RabbitTemplate.ConfirmCallback {
private Map<String /* TOPIC */, RabbitTemplate> rabbitMap = Maps.newConcurrentMap();
private Splitter splitter = Splitter.on("#");
private SerializerFactory serializerFactory = JacksonSerializerFactory.INSTANCE;
@Autowired
private ConnectionFactory connectionFactory;
@Autowired
private MessageStoreService messageStoreService;
public RabbitTemplate getTemplate(Message message) throws MessageRunTimeException {
Preconditions.checkNotNull(message);
String topic = message.getTopic();
RabbitTemplate rabbitTemplate = rabbitMap.get(topic);
if(rabbitTemplate != null) {
return rabbitTemplate;
}
log.info("#RabbitTemplateContainer.getTemplate# topic: {} is not exists, create one", topic);
RabbitTemplate newTemplate = new RabbitTemplate(connectionFactory);
newTemplate.setExchange(topic);
newTemplate.setRoutingKey(message.getRoutingKey());
newTemplate.setRetryTemplate(new RetryTemplate());
/**
* 添加实现了自定义序列化反序列化的converter对象
*/
// 创建自定义的 序列化对象
Serializer serializer = serializerFactory.create();
// 将该序列化对象 赋值给 转换类,帮助其实现 自定义Message和org.springframework.amqp.core.Message之间的转换
GenericMessageConverter gmc = new GenericMessageConverter(serializer);
// 装饰者对象,增加一些额外操作
RabbitMessageConverter rmc = new RabbitMessageConverter(gmc);
// 将 converter对象 赋值给 RabbitMQ 对应的的消息模板类
newTemplate.setMessageConverter(rmc);
String messageType = message.getMessageType();
if(!MessageType.RAPID.equals(messageType)) {
newTemplate.setConfirmCallback(this);
}
rabbitMap.putIfAbsent(topic, newTemplate);
return rabbitMap.get(topic);
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
}
}
这样就实现了 当我们发送自定义Message对象时,到达 RabbitMQ 的是 org.springframework.amqp.core.Message 类型的对象,当我们接收消息时,也会帮我们自动转换为 自定义的Message 对象。并且其中使用的是 jackson 序列化方法。