rabbitmq 六 生产者消息确认

import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeoutException;
/**
 * 现在:exchange交换机的topic模式
 * topic模式可以使用累心可以使用类似通配符一样的东西
 * 匹配规则:
 * 1.#代表零个或者多个字符
 * 2.*代表一个字符
 *
 * 场景
 * 红色,黄色,蓝色颜色的消息,分别发送到不同的队列,颜色只是其中的一个属性
 * 然后路由分别是:#.red.# 中间是红色的发送到red.queue队列
 * #.yellow.# 中间是黄色的发送到yellow.queue队列
 * *.blud.* 中间是蓝色的也发送到yellow.queue队列
 *
 * 在topic模式的基础上增加发布人 confirm模式
 * 三种方式:
 *        1.单条消息确认,同步等待消息确认   简单,速度慢
 *        2.批量确认消息,同步等待消息确认   简单/速度适中,但是很难判断是那条消息出问题
 *        3.异步处理,最佳的性能和资源利用,在错误的情况下能发现
 *
 *        消息确认:channel.addConfirmListener(param1,param2)监听, param1.消息成功处理  param2:消息到达exchange失败处理(可异常记录日志,或者尝试重新发送等)
 *                  channel.addReturnListener()监听,消息到达exchange,但是没有匹配到队列,返回消息
 */
public class ExchangeTest {

    private static final String EXCHANGE_NAME = "topic.exchange";
    private static final String RED_QUEUE = "red.queue";

    private static final String RED_ROUTING = "#.red.#";


    public static void main(String[] args) {

        new Thread(
                () -> {
                    /**
                     * 发送消息
                     */
                    ConnectionFactory factory = new ConnectionFactory();
                    factory.setHost("127.0.0.1");
                    factory.setUsername("rabbit");
                    factory.setPassword("rabbit");
                    //创建连接和通道
                    try (Connection conn = factory.newConnection(); Channel channel = conn.createChannel()) {

                        //------第一种简单设置,同步等待确认   begin--------
                        //声明交换机  topic模式
                        /*channel.exchangeDeclare(EXCHANGE_NAME, "topic");
                        //开启confirm模式
                        channel.confirmSelect();
                        for (int i = 0; i < 50; i++) {
                            //发送到red.queue队列
                            String message = "red rabbitmq ";
                            //发送到红色队列,匹配上面的路径#.red.#
                            channel.basicPublish(EXCHANGE_NAME, "red.less", null, message.getBytes(StandardCharsets.UTF_8));
                            //等待确认设置5秒超时时间   如果超时则抛出异常/重新发送消息
                            //channel.waitForConfirms(5000);
                        }*/
                        //------第一种简单设置,同步等待确认  end--------

                        //------第二种批量设置,同步等待确认   begin--------
                        //开启confirm模式
                        /*channel.confirmSelect();
                        int batchSize = 0;
                        for (int i = 0; i < 50; i++) {
                            batchSize++;
                            //发送到red.queue队列
                            String message = "red rabbitmq ";
                            //发送到红色队列,匹配上面的路径#.red.#
                            channel.basicPublish(EXCHANGE_NAME, "red.less", null, message.getBytes(StandardCharsets.UTF_8));
                            //等待确认设置5秒超时时间   如果超时则抛出异常/重新发送消息
                            if (batchSize == 10) {
                                channel.waitForConfirms(5000);
                                batchSize = 0;
                            }

                        }
                        if (batchSize >0) {
                            channel.waitForConfirms(5000);
                        }*/
                        //------第二种批量设置,同步等待确认  end--------

                        //------第三种异步设置,异步等待确认   begin--------
                        channel.confirmSelect();
                        int batchSize = 0;
                        for (int i = 0; i < 50; i++) {
                            batchSize++;
                            //发送到red.queue队列
                            String message = "red rabbitmq ";
                            ConcurrentNavigableMap<Long, String> map = new ConcurrentSkipListMap<Long, String>();

                            map.put(channel.getNextPublishSeqNo(), message);
                            channel.getNextPublishSeqNo();
                            ConfirmCallback commitBack = new ConfirmCallback() {
                                @Override//l  id, b true单条消息确认,false批量确认
                                public void handle(long l, boolean b) throws IOException {
                                    if (true) {
                                        //获取批量的数据,
                                        ConcurrentNavigableMap currentMap = map.headMap(l, true);
                                        currentMap.clear();
                                        System.out.println("批量,之前消息全部确认");
                                    } else {
                                        map.remove(l);
                                        System.out.println("单条消息确认");
                                    }
                                }
                            };
                            channel.addConfirmListener(commitBack, (seq, multi)->{
                                //未发送消息到交换机exchange,可根据情况是否再次发送
                                System.err.println("消息发送失败seq"+seq+";mes:"+message);
                                commitBack.handle(seq, multi);
                            });
                            channel.addReturnListener(new ReturnListener() {
                                @Override//达到交换机,但是没有路由匹配
                                public void handleReturn(int i, String s, String s1, String s2, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                                    //根据情况是否重新发送
                                    System.err.println("消息发送失败code"+i+";mes:"+new String(bytes, StandardCharsets.UTF_8));
                                }
                            });
                            //发送到红色队列,匹配上面的路径#.red.#
                            channel.basicPublish(EXCHANGE_NAME, "red.less", null, message.getBytes(StandardCharsets.UTF_8));
                        }
                        //------第三种异步设置,异步等待确认  end--------

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
        ).start();
        //消费者1
        new Thread(
                () -> {
                    //接收消息
                    ConnectionFactory comsumerFacotry = new ConnectionFactory();
                    comsumerFacotry.setHost("127.0.0.1");
                    comsumerFacotry.setUsername("rabbit");
                    comsumerFacotry.setPassword("rabbit");

                    Connection comsumerConn = null;
                    try {
                        //这里不手动关闭连接和通道,因为需要监听器一直监听是否有消息,所以需要一直保持连接
                        comsumerConn = comsumerFacotry.newConnection();
                        Channel channel = comsumerConn.createChannel();
                        //声明交换机  topic模式
                        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
                        //声明队列RED_QUEUE
                        channel.queueDeclare(RED_QUEUE, false, false, false, null);
                        //绑定交换机和队列
                        channel.queueBind(RED_QUEUE, EXCHANGE_NAME, RED_ROUTING);
                        //消息监听器
                        boolean autoAck = true;//是否自动ack   接收到消息则认为成功

                        channel.basicConsume(RED_QUEUE, autoAck, (consumerTag, message) -> {
                            System.out.println("消费者 红色收到消息:" + new String(message.getBody(), StandardCharsets.UTF_8));
                        }, consumerTag -> {
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        e.printStackTrace();
                    }
                }
        ).start();
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值