原生 API

同步发送

生产者

// 创建一个生产者  (制定一个组名)
DefaultMQProducer producer = new DefaultMQProducer("test-producer-group");
// 连接 name server
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
// 启动
producer.start();
// 创建10个消息,消息将分摊到 4 个队列上 2-2-3-3
for (int i = 0; i < 10; i++) {
    Message message = new Message("testTopic", "我是一个简单的消息".getBytes());
    // 发送消息
    SendResult sendResult = producer.send(message);
    System.out.println(sendResult.getSendStatus());
}
// 关闭生产者
producer.shutdown();

消费者

// 创建一个消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test-consumer-group");
// 连接namesrv
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
// 订阅一个主题  * 标识订阅这个主题中所有的消息,后面说 tag 过滤
consumer.subscribe("testTopic", "*");
// 设置一个监听器 (一直监听的, 异步回调方式),并发模式
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        // 这个就是消费的方法 (业务处理)
        System.out.println("我是消费者");
        System.out.println(msgs.get(0).toString());
        System.out.println("消息内容:" + new String(msgs.get(0).getBody()));
        System.out.println("消费上下文:" + context);
        // 返回值 CONSUME_SUCCESS 成功,消息会从mq出队
        // 返回值 RECONSUME_LATER 失败, 消息会重新回到队列(默认消费重试16次)
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
// 启动
consumer.start();

异步发送

DefaultMQProducer producer = new DefaultMQProducer("async-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
Message message = new Message("asyncTopic", "我是一个异步消息".getBytes());
producer.send(message, new SendCallback() {
    @Override
    public void onSuccess(SendResult sendResult) {
        System.out.println("发送成功");
    }

    @Override
    public void onException(Throwable e) {
        System.err.println("发送失败:" + e.getMessage());
    }
});
System.out.println("我先执行");

单向发送

DefaultMQProducer producer = new DefaultMQProducer("oneway-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
Message message = new Message("onewayTopic", "日志xxx".getBytes());
producer.sendOneway(message);
System.out.println("成功");
producer.shutdown();

批量发送

生产者

// 创建默认的生产者
DefaultMQProducer producer = new DefaultMQProducer("batch-producer-group");
// 设置nameServer地址
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
// 启动实例
producer.start();
List<Message> msgs = Arrays.asList(
        new Message("batchTopic", "我是一组消息的A消息".getBytes()),
        new Message("batchTopic", "我是一组消息的B消息".getBytes()),
        new Message("batchTopic", "我是一组消息的C消息".getBytes())
);
// 发送一组消息,这是一次发送,这批次的消息会被放到一个队列上
SendResult send = producer.send(msgs);
System.out.println(send);
// 关闭实例
producer.shutdown();

消费者

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("batch-consumer-group");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("batchTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        // 会打印 3 次
        System.out.println("收到消息了" + new Date());
        System.out.println(msgs.size());
        System.out.println(new String(msgs.get(0).getBody()));
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

延迟消息

DefaultMQProducer producer = new DefaultMQProducer("ms-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
Message message = new Message("orderMsTopic", "订单号,座位号".getBytes());
// 给消息设置一个延迟时间
// messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"
message.setDelayTimeLevel(3);
// 发延迟消息
producer.send(message);
System.out.println("发送时间" + new Date());
producer.shutdown();

顺序消息

  1. 因为消费者默认并发模式,也就是多线程,多线程是需要抢夺 cpu 调度权的,多线程天生不能保证顺序
  2. 就算改为单线程也不能保证顺序,假设 Topic 2 个队列,一个是空的一个有3条消息,消费者轮询取消息

所以要保证顺序就需要满足两个条件:1,单线程模式消费;2,消息放到一个队列或 topic 只设置一个队列

生产者

DefaultMQProducer producer = new DefaultMQProducer("orderly-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();

msgModels.forEach(msgModel -> {
    Message message = new Message("orderlyTopic", msgModel.toString().getBytes());
    try {
        // msgModel.getOrderSn() 订单号,表示同一个订单号的发到一个队列
        producer.send(message, new MessageQueueSelector() {
            // arg 就是 msgModel.getOrderSn()
            @Override
            public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                int hashCode = arg.toString().hashCode();
                // 2 % 4 =2
                // 3 % 4 =3
                // 4 % 4 =0
                // 5 % 4 =1
                // 6 % 4 =2  周期性函数
                int i = hashCode % mqs.size();
                return mqs.get(i);
            }
        }, msgModel.getOrderSn());

    } catch (Exception e) {
        e.printStackTrace();
    }
});
producer.shutdown();
System.out.println("发送完成");

消费者

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("orderly-consumer-group");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("orderlyTopic", "*");
// MessageListenerConcurrently 并发模式 多线程的  重试16次
// MessageListenerOrderly 顺序模式 单线程的  无限重试(次数为 Integer.Max_Value)
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
        System.out.println("线程id:" + Thread.currentThread().getId());
        System.out.println(new String(msgs.get(0).getBody()));
        return ConsumeOrderlyStatus.SUCCESS;
    }
});
consumer.start();

带 Tag

生产者

DefaultMQProducer producer = new DefaultMQProducer("tag-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
Message message = new Message("tagTopic", "vip1", "我是vip1的文章".getBytes());
Message message2 = new Message("tagTopic", "vip2", "我是vip2的文章".getBytes());
producer.send(message);
producer.send(message2);
System.out.println("发送成功");
producer.shutdown();

消费者1

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-a");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
// 只接收 vip1 的消息
consumer.subscribe("tagTopic", "vip1");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        System.out.println("我是vip1的消费者,我正在消费消息" + new String(msgs.get(0).getBody()));
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

消费者2

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-b");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
// vip1 vip2 的消息都接收
consumer.subscribe("tagTopic", "vip1 || vip2");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        System.out.println("我是vip2的消费者,我正在消费消息" + new String(msgs.get(0).getBody()));
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

带 Key

生产者

DefaultMQProducer producer = new DefaultMQProducer("key-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
String key = UUID.randomUUID().toString();
System.out.println(key);
Message message = new Message("keyTopic", "vip1", key, "我是vip1的文章".getBytes());
producer.send(message);
System.out.println("发送成功");
producer.shutdown();

消费者

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("key-consumer-group");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("keyTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        MessageExt messageExt = msgs.get(0);
        System.out.println("我是vip1的消费者,我正在消费消息" + new String(messageExt.getBody()));
        System.out.println("我们业务的标识:" + messageExt.getKeys());
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

重试

生产者

DefaultMQProducer producer = new DefaultMQProducer("retry-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
// 生产者发送消息 重试次数
producer.setRetryTimesWhenSendFailed(2);
producer.setRetryTimesWhenSendAsyncFailed(2);
String key = UUID.randomUUID().toString();
System.out.println(key);
Message message = new Message("retryTopic", "vip1", key, "我是vip666的文章".getBytes());
producer.send(message);
System.out.println("发送成功");
producer.shutdown();

消费者

/**
 * 重试的时间间隔
 * 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
 * 默认重试16次
 * 1.能否自定义重试次数
 * 2.如果重试了16次(并发模式) 顺序模式下(int最大值次)都是失败的?  是一个死信消息 则会放在一个死信主题中去 主题的名称:%DLQ%retry-consumer-group
 * 3.当消息处理失败的时候 该如何正确的处理?
 * --------------
 * 重试的次数一般 5次
 * @throws Exception
 */
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-consumer-group");
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("retryTopic", "*");
// 设定重试次数
consumer.setMaxReconsumeTimes(2);
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        MessageExt messageExt = msgs.get(0);
        System.out.println(new Date());
        System.out.println(messageExt.getReconsumeTimes());
        System.out.println(new String(messageExt.getBody()));
        // 业务报错了 返回null 返回 RECONSUME_LATER 都会重试
        return ConsumeConcurrentlyStatus.RECONSUME_LATER;
    }
});
consumer.start();
posted @ 2024-07-22 22:20  CyrusHuang  阅读(1)  评论(0编辑  收藏  举报