RabbitMQ 交换机

5. 交换机

5.1 Exchanges

RabbitMQ消息传递模型的思想是:生产者生产的消息从不会直接发送到队列;相反,生产者只能将消息发送到交换机,一方面,他接收到生产者的信息,另一方面,将他们推入队列

5.1.1 Exchange的类型

直接(direct)、主题(topic)、标题(headers)、扇出(发布/订阅:fanout)

5.1.2 无名(默认)Exchange

channel.basicPublish("", queueName, null, message.getBytes(StandardCharsets.UTF_8));

之前使用的 “” 就是默认交换机

5.1.3 绑定(binding)

binding就是exchange和queue的桥梁,由他指定交换机和哪些队列进行绑定

在这里插入图片描述

5.2 Fanout 扇出交换机

5.2.1 fanout简介

fanout就是一种发布/订阅模式,他将接收到的消息广播到他知道的所有队列中

5.2.2 编码实现

一个发送,两个接收

/**
 * 消息的接收
 */
public class ReceiveLog1 {
    public static final String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        //声明队列 临时队列队,列名称随机
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机与队列
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        System.out.println("等待接收消息,接收到消息打印...");
        channel.basicConsume(queueName, true, (consumerTag, message) -> {
            System.out.println("ReceiveLog1接收到的消息:" + new String(message.getBody()));
        }, (consumerTag) -> {}
        );
    }
}
/**
 * 消息的接收
 */
public class ReceiveLog2 {
    public static final String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();
        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        //声明队列 临时队列队,列名称随机
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机与队列
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        System.out.println("等待接收消息,接收到消息打印...");
        channel.basicConsume(queueName, true, (consumerTag, message) -> {
            System.out.println("ReceiveLog2接收到的消息:" + new String(message.getBody()));
        }, (consumerTag) -> {}
        );
    }
}
/**
 * 发送消息
 */
public class EmitLog {
    //交换机名称
    public static final String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();

        //声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String message = scanner.next();
            //1:交换机名 2:routingKey 3:其它参数 4:发送的消息
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
            System.out.println("发送的消息:" + message);
        }
    }
}

5.3 Direct 直接交换机

5.3.1 Direct简介

Direct模式其实就是路由模式。在fanout(发布/订阅)模式中,发送信息时,会发送到exchange中,绑定了该交换机的队列都会接收到消息,那是因为绑定的routingKey值都是相同的。当routeKey值不同时,发送消息时可以通过指定的routingKey值发送给特定的队列。这就是路由模式(Direct)。

在这里插入图片描述

5.3.2 案例

实现以下direct模式:当交换机指定不同routingKey时,发送到不同队列

在这里插入图片描述

/**
 * 接收console队列的消息
 */
public class ReceiveLogsDirect1 {

    public static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitMqUtils.getChannel();
        //声明一个交换机 1:交换机名 2:模式
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        //声明队列 1:队列名 2:是否持久化 3:是否共享 4:是否自动删除 5:其它参数
        channel.queueDeclare("console", false, false, false, null);
        //绑定 1:队列名 2:交换机名 3:routingKey
        channel.queueBind("console", EXCHANGE_NAME, "info");
        channel.queueBind("console", EXCHANGE_NAME, "warning");

        //消费消息 1:队列名 2:自动应答 3:消费成功回调 4:消费取消回调
        channel.basicConsume("console", true, (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect1接收到的消息:" + new String(message.getBody()));
        }, (consumerTag) -> {
        });
    }
}
/**
 * 接收disk队列的消息
 */
public class ReceiveLogsDirect2 {

    public static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitMqUtils.getChannel();
        //声明一个交换机 1:交换机名 2:模式
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        //声明队列 1:队列名 2:是否持久化 3:是否共享 4:是否自动删除 5:其它参数
        channel.queueDeclare("disk", false, false, false, null);
        //绑定交换机和队列 1:队列名 2:交换机名 3:routingKey
        channel.queueBind("disk", EXCHANGE_NAME, "error");

        //消费消息 1:队列名 2:自动应答 3:消费成功回调 4:消费取消回调
        channel.basicConsume("disk", true, (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect2接收到的消息:" + new String(message.getBody()));
        }, (consumerTag) -> {
        });
    }
}
/**
 * 发送消息
 */
public class DirectLogs {
    //交换机名称
    public static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();

        Map<String, String> map = new HashMap<>();
        map.put("info", "info...");
        map.put("warning", "warning...");
        map.put("error", "error...");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String message = entry.getValue();
            //发送信息并指定交换机和routingKey 1:交换机名 2:routingKey 3:其它参数 4:发送的消息
            channel.basicPublish(EXCHANGE_NAME, entry.getKey(), null, 
                                 message.getBytes(StandardCharsets.UTF_8));
            System.out.println("发送的消息:" + message);
        }
    }
}

5.4 Topic 主题交换机

5.4.1 Topic 简介及规范

routingKey支持类似正则的规范,可以匹配一类具体的routingKey。相比于fanout和direct更灵活。

规范:

  • 必须是一个单词列表,以点号分隔开。如:user.man.young.a
  • ***** 号可以代替一个单词 。如:一共三个单词且中间单词是user:*.user.*,一共三个单词且最后一个单词是abc: *.*.abc
  • # 号可以代替零个或多个单词。如:第一个单词是user:user.#
  • 当队列绑定的routingKey是 # 号,那么这个队列将接受所有数据,如同fanout
  • Topic模式包含了fanout和direct模式

5.4.2 案例

在这里插入图片描述

/**
 * 主题交换机 消费者C1
 */
public class ReceiveLogsTopic1 {
    //交换机名称
    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitMqUtils.getChannel();
        //声明交换机 topic
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        //声明队列 1:队列名 2:持久化 3:共享 4:自动删除 5:其他信息
        channel.queueDeclare("Q1", false, false, false, null);
        //绑定 1:队列名 2:交换机名 3:routingKey
        channel.queueBind("Q1", EXCHANGE_NAME, "*.orange.*");
        System.out.println("等待接收消息");
        //1:队列名 2:自动应答 3:消费成功回调 4:消费取消回调
        channel.basicConsume("Q1", true, (consumerTag, message) -> {
            System.out.println("接收到routingKey=" + message.getEnvelope().getRoutingKey() + "的消息:" + new 
                               String(message.getBody()));
        }, (consumerTag) -> {
        });
    }
}
/**
 * 主题交换机 消费者C2
 */
public class ReceiveLogsTopic2 {
    //交换机名称
    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitMqUtils.getChannel();
        //声明交换机 topic
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        //声明队列 1:队列名 2:持久化 3:共享 4:自动删除 5:其他信息
        channel.queueDeclare("Q2", false, false, false, null);
        //绑定 1:队列名 2:交换机名 3:routingKey
        channel.queueBind("Q2", EXCHANGE_NAME, "*.*.rabbit");
        channel.queueBind("Q2", EXCHANGE_NAME, "lazy.#");
        System.out.println("等待接收消息");
        //1:队列名 2:自动应答 3:消费成功回调 4:消费取消回调
        channel.basicConsume("Q2", true, (consumerTag, message) -> {
            System.out.println("接收到routingKey=" + message.getEnvelope().getRoutingKey() + "的消息:" + new 
                               String(message.getBody()));
        }, (consumerTag) -> {
        });
    }
}
/**
 * 生产者:发送消息
 */
public class EmitLogTopic {
    //交换机名称
    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();

        //*.*.rabbit  lazy.#  *.orange.*
        Map<String, String> binding = new HashMap<>();
        binding.put("a.orange.rabbit", "a.orange.rabbit...");
        binding.put("lazy.orange.abc", "lazy.orange.abc...");
        binding.put("lazy.orange.rabbit", "lazy.orange.rabbit...");
        binding.put("abc.rabbit.orange", "abc.rabbit.orange...");
        binding.put("abc.orange.efg", "abc.orange.efg...");
        binding.put("lazy.123.efg", "lazy.123.efg...");
        for (Map.Entry<String, String> entry : binding.entrySet()) {
            String message = entry.getValue();
            //发送信息并指定交换机和routingKey 1:交换机名 2:routingKey 3:其它参数 4:发送的消息
            channel.basicPublish(EXCHANGE_NAME, entry.getKey(), null, 
                                 message.getBytes(StandardCharsets.UTF_8));
            System.out.println("发送的消息:" + message);
        }
    }
}

第六章:RabbitMQ 死信队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值