RabbitMQ——交换机

 

 

张图画得非常形象,发布者和订阅者之间,不是直接和队列关联,还有交换机这一层。发布者将消息传递给交换机,交换机将消息分发到不同的队列,消费者选择队列读取消息。

因为多了一层交换机,发布者和消费者的关系变得非常灵活,发布者和队列之间,可以是1-n的关系,队列和订阅者,也可以是1-n的关系,能适配非常多复杂的业务场景。

功能概述:交换机介于发布者和队列之间,发布者可以通过交换机,将消息分发到一个或多个队列上。

常用的交换机

Direct Exchange ,

直连交换机,通过队列ID进行精准匹配。

Fanout Exchange

扇出交换机,消息会分配给每一个与交换机关联的队列。

Topic Exchange

主题交换机,通过模糊匹配的方式,将消息分配给命中的队列。

匹配规则:

*  (星号) 用来表示一个单词 (必须出现的)
#  (井号) 用来表示任意数量(零个或多个)单词


当一个队列的绑定键为 "#"(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机等价于直连交换机。
因此,通过主题交换机,可以实现扇形交换机和直连交换机的功能。

另外还有 Header Exchange 头交换机 ,Default Exchange 默认交换机,Dead Letter Exchange 死信交换机。

 

测试用代码

发布者

/**
 * @author Mr.css
 * @date 2020-11-12 19:30
 */
public class Send {
    /**
     * 队列名称
     */
    private static final String QUEUE_NAME = "queue_name";
    /**
     * 路由键,交换机会根据路由键,把消息推到队列,
     * 如果路由键与队列名称一致的情况,消息会被精准推送到同名的队列
     * (根据交换机的类型,设置不同的路由键)
     */
    private static final String ROUTING_KEY = "queue_name";
    /**
     * 交换机名称
     */
    private static final String EXCHANGE = "exchanges";

    public static void main(String[] args) {
        try {
            Connection connection = ConnectionUtil.getConnection();
            Channel channel = connection.createChannel();
            //声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //声明交换机,可以修改 BuiltinExchangeType 测试不同的交换机效果
            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);

            int cnt = 10;
            while (cnt-- > 0) {
                String message = "This is simple queue:" + cnt;

                //BasicProperties:和http协议类似,是允许添加请求头的,MQ也有这样的设计
                AMQP.BasicProperties properties = MessageProperties.BASIC.builder().build();

                //通过交换机,把消息发送到推送到队列中
                channel.basicPublish(EXCHANGE, ROUTING_KEY, properties, message.getBytes(Charset.defaultCharset()));
                System.out.println("[send]:" + message);
            }

            channel.close();
            connection.close();
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

订阅者

/**
 * @author Mr.css
 * @date 2020-11-12 19:31
 */
public class Receive {
    private static final String QUEUE_NAME = "queue_name";

    public static void main(String[] args) {
        try {
            Connection connection = ConnectionUtil.getConnection();
            Channel channel = connection.createChannel();
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);

            //限制消息接收的数量
            channel.basicQos(0,1,false);

            DefaultConsumer consumer = new DefaultConsumer(channel) {

                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) {
                    //查看消息主体内容
                    String message = new String(body, StandardCharsets.UTF_8);
                    System.out.println("[Receive]:" + message);

                    //查看请求头
                    System.out.println(properties);

                    //查看消息的发送情况
                    System.out.println(envelope);

                    try {
                        //模拟超时的情况
                        Thread.sleep(500);
                        //手动应答
                        channel.basicAck(envelope.getDeliveryTag(), false);
                    } catch (InterruptedException | IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            //自动应答设置为false
            channel.basicConsume(QUEUE_NAME, false, consumer);
        } catch (IOException | ShutdownSignalException | ConsumerCancelledException e) {
            e.printStackTrace();
        }
    }
}

 

posted on 2022-04-01 09:49  疯狂的妞妞  阅读(83)  评论(0编辑  收藏  举报

导航