初识RabbitMq(3)发布/订阅模式和路由模式

发布——订阅(Publish/Subscribe)

工作队列背后的假设是,每个任务都恰好交付给一个工人。在这一部分中,我们将做一些完全不同的事情-我们将相同消息传达给多个消费者。这种模式称为“发布/订阅”。

通过交换机完成此模式,生产者——》交换机——》多个队列!!!——》不同的消费者。达成不同消费者接收同一台消息。

img

利用广播类型的交换机,交换机自动生成排他队列 ,消费者与交换机绑定,交换机与生成的队列绑定,消费者监听绑定交换机生成的一个队列!达到将一条消息发给多个消费者的目的。

生产者

/*
* 发布/订阅队列-广播模式-生产者
* */
public class Send {
    //交换机名称
    private final static String EXCHANGE_NAME = "ps_fanout";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("");
        factory.setUsername("");
        factory.setPassword("");
        factory.setVirtualHost("");
        //try cache新写法
        try (
                //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
                Connection connection = factory.newConnection();
                //创建信道
                Channel channel = connection.createChannel()) {
                    //绑定交换机 交换机名字 交换机类型:广播
                    channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
                    //message内容
                    String message = "Hello World!ps_fanout";
                    //发送消息 交换机
                    channel.basicPublish(EXCHANGE_NAME,"", null, message.getBytes(StandardCharsets.UTF_8));
                    System.out.println(" [x] Sent '" + message + "'");
                }
    }
}

消费者

/*
* 布/订阅队列-广播模式-消费者1
* */
public class Recv {
    private final static String EXCHANGE_NAME = "ps_fanout";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("");
        factory.setUsername("");
        factory.setPassword("");
        factory.setVirtualHost("");
        //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        //绑定交换机
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
        //获取队列名
        String queueName = channel.queueDeclare().getQueue();
        //将交换机和队列绑定
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            //拿到消息
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        //监听队列 消费消息
        //队列名称 自动回执
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
    }
}

优缺点

实时上从工作队列的公平模式开始就不存在缺点了,只是有的需求无法实现,对于发布订阅模式无法实现将消息发给特定消费者的需求,因为是群发!所以需要路由模式。

路由模式(Routing)

img

根据routing-key绑定交换机和队列,发送消息时携带routing-key,交换机根据routing-key发送到指定队列。

生产者

/*
* 路由队列-生产者
* */
public class Send {
    //交换机名称
    private final static String EXCHANGE_NAME = "routing_direct";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("");
        factory.setUsername("");
        factory.setPassword("");
        factory.setVirtualHost("");
        //try cache新写法
        try (
                //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
                Connection connection = factory.newConnection();
                //创建信道
                Channel channel = connection.createChannel()) {
                    //绑定交换机 交换机名字 交换机类型:广播
                    channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
                    //message内容
                    String info_message = "Hello World!info";
                    String waring_message = "Hello World!waring";
                    String error_message = "Hello World!error";
                    String infoRoutingKey="info";
                    String waringRoutingKey="waring";
                    String errorRoutingKey="error";
                    //发送消息 交换机
                    channel.basicPublish(EXCHANGE_NAME,infoRoutingKey, null, info_message.getBytes(StandardCharsets.UTF_8));
                    channel.basicPublish(EXCHANGE_NAME,waringRoutingKey, null, waring_message.getBytes(StandardCharsets.UTF_8));
                    channel.basicPublish(EXCHANGE_NAME,errorRoutingKey, null, error_message.getBytes(StandardCharsets.UTF_8));
                    System.out.println(" [x] Sent '" + info_message + "'");
                    System.out.println(" [x] Sent '" + waring_message + "'");
                    System.out.println(" [x] Sent '" + error_message + "'");
                }
    }
}

消费者

/*
* 路由队列-消费者1
* */
public class Recv {
    private final static String EXCHANGE_NAME = "routing_direct";

    public static void main(String[] argv) throws Exception {
        //创建连接工厂 port默认不用配置
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("");
        factory.setUsername("");
        factory.setPassword("");
        factory.setVirtualHost("");
        //用连接工厂 创建连接 Connection继承了Closeable接口可以自动关闭
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        //绑定交换机
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        //获取队列名
        String queueName = channel.queueDeclare().getQueue();
        //将交换机和队列绑定
        String errorRoutingkey="error";
        channel.queueBind(queueName, EXCHANGE_NAME, errorRoutingkey);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            //拿到消息
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        //监听队列 消费消息
        //队列名称 自动回执
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
    }
}

在不指定交换机时使用默认交换机,类型direct!routingkey是队列名称。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值