RabbitMQ ---发布 / 订阅

Exchanges 交易所

rabbitmq 中消息传递模型的核心思想是:生产者永远不会将任何消息直接发送到队列。实际上,生产者通常甚至不知道消息是否会被传递到任何队列。
相反,生产者只能向交易所(Exchanges)发送消息。交换是一件非常简单的事。一方面,它接收来自生产者的消息,另一方面将它们推送到队列。交易所必须确切知道如何处理它收到的消息,它应该附加到特定队列吗?他应该附加到多个队列吗?或者他应该被丢弃吗?其规则由 交换类型定义(Exchanges type)。
交换类型有几种可供选择:直接direct , 主题topic , 标题headers , 扇出fanout 。创建一个名为logs的fanout交换类型。

channel.exchangedeclare("logs",fanout);

fanout 交换,他只能将收到的所有信息广播到他知道的其他队列中。

回想一下我们之前如何发布消息的:channel.basicPublish("","hello",null,massage.getBytes());
第一个参数就是交换的名称。默认是无名交换就是通过空字符串(“”)来识别的。rabbitmqctl list_exchanges 命令用来查看服务器上所有的交换列表。消息通过routingKey指定的名称的路由到队列(如果存在)。
现在发布到logs交换
channel.basicPublish("logs","hello",null,massage.getBytes());

临时队列 Temporary queues

成功连接到rabbitmq后,默认创建出临时队列(有待考察,一个连接能使用多少个临时队列)。
断开消费者时,临时队列会自动删除。
临时队列只针对流动数据,当你想要在生产者和消费者之间共享队列时使用。

// 获得一个临时队列
channel.queueDeclare();
// 获得临时队列的名称  
String queueName = channel.queueDeclare().getQueue();

绑定 Bindings

告诉交换机将消息发送到我们的队列,交换机和队列之间的关系为绑定 Binding

channel.queueBind( queueName , "logs" , " " ); // logs交换机将消息附加到我们的队列中。

rabbitmqctl list_bindings 命令是列出所有的绑定

贴代码

// 生产者
public class SendLog {
    final static String EXCHANG_NAME = "logs";
    static ConnectionUtil connUtil = new ConnectionUtil();
    public static void main(String[] args) throws Exception {
        Connection conn = connUtil.getConn();
        Channel channel = conn.createChannel();
        // 声明交换机 参数1是交换机名称 参数2是交换机类型
        channel.exchangeDeclare(EXCHANG_NAME,"fanout");
        // 模拟多次发送消息到交换机
        for (int i = 0; i<10; i++){
            String message = "this is logs Exchange , Number is "+i;
            //参数1是交换机名称 2rontingKey秘钥值fanout类型会默认忽略秘钥这里不能写null   4是字节串
            channel.basicPublish(EXCHANG_NAME, "",null,message.getBytes());
            System.out.println("发送:"+message);
            // 模拟 时间间隔 看上去有点忙、
            Thread.sleep(1000);
        }
        // 关闭通道和连接
        channel.close();
        conn.close();
    }
}

// 消费者
public class Receiverlog {
    final static String EXCHANG_NAME = "logs";
    static ConnectionUtil connUtil = new ConnectionUtil();
    public static void main(String[] args)  throws Exception {
        Connection conn = connUtil.getConn();
        Channel channel = conn.createChannel();
        // 声明交换机 定义交换机类型
        channel.exchangeDeclare(EXCHANG_NAME, "fanout");
        // 获取临时队列名称
        String queueName = channel.queueDeclare().getQueue();
        // 绑定交换机,参数3是routingKey秘钥的值
        channel.queueBind(queueName, EXCHANG_NAME, "");
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" 接受请求: '" + message + "'");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {});
    }
}

注意:

1. 上面的案例中使用的是临时队列,结合临时队列的特性。
2. 生产者下channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes("UTF-8)); 第二个参数不能使用 null代替,这是rontingKey 参数的存放位置。

生产者中没有定义队列,直接将消息传到了交换机中的临时队列中,消费者在线会立即使用。如果是多个消费者情况,每个消费者获得消息是一样的,这是fanout类型特性,他只能将收到的所有信息广播到他知道的其他队列中。。如果没有消费者在线,那交换机中的消息会舍弃掉,因为我们使用的是临时队列。

猜你喜欢

转载自blog.csdn.net/liguangix/article/details/88308903