RabbitMQ之序列化与反序列化:自定义某个Object对象和Spring中的某个Object对象通过序列化和反序列化的方式进行转换(java代码实现)

本博客属于 《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 序列化方法。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,可以使用RabbitMQ进行消息传递,并且可以对对象进行序列化反序列化。下面是一个示例代码,展示了如何使用RabbitMQJava对象进行序列化。 首先,你需要在你的项目引入RabbitMQ的相关依赖。可以在Maven添加以下依赖项: ```xml <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.12.0</version> </dependency> ``` 接下来,你需要创建一个Java对象,该对象需要实现`Serializable`接口,以便能够在网络上进行序列化反序列化。例如: ```java import java.io.Serializable; public class Message implements Serializable { private String content; public Message(String content) { this.content = content; } public String getContent() { return content; } } ``` 然后,你可以使用RabbitMQ发送和接收消息。下面是一个简单的示例: ```java import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MessageProperties; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.concurrent.TimeoutException; public class RabbitMQExample { private static final String QUEUE_NAME = "my_queue"; public static void main(String[] args) { // 创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { // 创建队列 channel.queueDeclare(QUEUE_NAME, true, false, false, null); // 发送消息 Message messageToSend = new Message("Hello RabbitMQ!"); byte[] serializedMessage = serializeObject(messageToSend); channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, serializedMessage); // 接收消息 channel.basicConsume(QUEUE_NAME, true, (consumerTag, delivery) -> { Message receivedMessage = (Message) deserializeObject(delivery.getBody()); System.out.println("Received message: " + receivedMessage.getContent()); }, consumerTag -> {}); } catch (IOException | TimeoutException | ClassNotFoundException e) { e.printStackTrace(); } } private static byte[] serializeObject(Object object) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(object); oos.flush(); return bos.toByteArray(); } private static Object deserializeObject(byte[] bytes) throws IOException, ClassNotFoundException { ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } } ``` 在上面的示例,`serializeObject`和`deserializeObject`方法分别将Java对象序列化为字节数组和将字节数组反序列化Java对象。通过调用`basicPublish`方法,可以将序列化后的消息发送到指定的队列。 使用RabbitMQ进行对象序列化时,需要确保发送方和接收方都可以访问相同的对象类定义。否则,可能会导致反序列化失败。 希望以上信息能对你有所帮助!如有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值