消息队列的实现

598 阅读2分钟

这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

mq消息的优点大家都知道,可以削峰和解耦,减缓高峰流量,降低系统压力,减少并发问题,将业务功能执行拆解开来。

实现系统之间的并行执行:

比如中台服务中,不同的中台服务之间可以通过异步消息的方式进行信息传递,而且可以不需要考虑上下游业务的处理结果,也不受上下游业务结果的影响。当然也可以自己生产消息自己消费。

解耦的场景比如说,两个有关联的功能逻辑,买票系统和车票库存系统,当下单买票时,车票库存系统出现故障,两个系统之间通过消息队列进行关联,则库存系统的异常不会影响买票下单的正常进行,因为系统之间是通过异步消息去通知库存系统进行车票库存的增减。

下面用一个实际例子展示消息队列的实现。

消息生产者
/**
 * 消息生产者,可以是在业务逻辑方法中进行调用,比如工单创建完成的消息,后续进行异步消费用的
 * 当然消息也可以是延迟发送的
 *
 * 
 */
private void orderPassMessage(TestDTO testdto, MQTypeEnum MqType) {
    Map params = Maps.newHashMapWithExpectedSize(6);
    params.put("MqType", MqType);
    params.put("Code", "");
    params.put("id", "123456jdiwuidnkqwdnkajsd");
    params.put("user", "MyTest");
​
    MqTestDemoMessage.sendMessage(params);
}
/**
 * 封装好的消息体内容
 */
public static void sendMessage(Map params) {
//消息中一定要包含时间
    Date date = new Date();
    Map headers = MessageHeaders.headers()
    //要设置一个有一定的业务含义的Tag,作为消息监控方在消费消息时的依据
    //还要传入一些必要的业务参数
            .setTag("Test_TAG_DEMO_ONE")
            .setCode("mq_test_code")
            .setTime(date)
            .setOutId("99999")
            .setDelay(MessageProducer.FIVE_SECONDS)
            .build();
    params.put("date", DateFormatUtils.format(date, TestDateUtils.DATE));
    
    log.info("TestMqMessage sendMessage to other object ,headers={},params={}", headers,params);
    producer.sendMessage(JSONObject.toJSONString(params), headers);
}
消息消费者
/**
 *  消费方
 *  Code=mq_test_biz_code, x-delay=5000, tag=Test_TAG_DEMO_ONE
 * @param params
 * @param headers
 * 消息队列的名称TestMqDemoSink,如果消息消费失败,会进入死信队列
 */
@StreamListener(value = TestMqDemoSink.INPUT, condition = "headers['tag']=='Test_TAG_DEMO_ONE' OR headers['Code']=='mq_test_code'")
//这里就是监控消息的依据,根据headers里面的tag和bizCode来进行消息的过滤,两个条件的或的关系,当然也可以是且的关系。
public void MqTestSendMessage(@Payload String params, @Headers MessageHeaders headers) {
//日志打印一下接收到的消息体内容
    log.info("MqTestSendMessage params: {}, headers: {}", params, headers);
​
    MessageHeaders headersTest = new MessageHeaders(headers);
    JSONObject eventParams = JSON.parseObject(params);
    BaseResponse response = TestProService.execute(eventParams);
    if (!ResponseCodeEnum.SUCCESS.equals(response.getCode())) {
        log.error(" test MqDemoTest error response:{}", JSON.toJSONString(response));
        return;
    }
}
//指定的消息队列
public interface TestMqDemoSink {
    String INPUT = "testMqDemoInput";
​
    @Input(TestMqDemoSink.INPUT)
    SubscribableChannel input();
}