RabbitMQ 入门 (三) Exchange三种模式 —发布订阅、路由、通配

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zl_momomo/article/details/83026838

Exchange

RabbitMQ的消息队列模型的核心概念是:生产者从不直接往队列里发送任何消息。实际上,多数情况下生产者甚至不知道消息是否会被发送到队列里。

与此相反,生产者只能将消息发送到一个交换器里。交换器做的事情很简单。一方面它接收生产者发送过来的消息,另一方面它将收到的消息推入队列里。交换器必须明确对于收到的消息它该怎么处理。这条消息是否应该附加到某个特定的队列后面?这条消息是否应该附加到多个队列后面?这条消息是否应该被丢弃?这些规则都由交换器类型(exchange type)来定义。


RabbitMQ常用的Exchange Type有fanout(广播交换器)、direct(直连交换器)、topic(主题交换器)、headers(头部交换器)这四种。

1.Publisher/Subscribe(发布/订阅) -fanout type

Sending messages to many consumers at once(同时向许多消费者发送消息)

一个生产者,多个消费者,每一个消费者都有自己的一个队列,生产者没有将消息直接发送到队列,而是发送到了交换机,每个队列绑定交换机,生产者发送的消息经过交换机,到达队列,实现一个消息被多个消费者获取的目的。需要注意的是,如果将消息发送到一个没有队列绑定的exchange上面,那么该消息将会丢失,这是因为在rabbitMQ中exchange不具备存储消息的能力,只有队列具备存储消息的能力。 

//发布者
public class Publisher {
    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        String[] messages = new String[]{"First message.", "Second message..",
                "Third message...", "Fourth message....", "Fifth message....."};
        for(String message : messages){
            //第二个参数为选择键
            channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
            System.out.println("[x] sent " + message);
        }
        channel.close();
        connection.close();
    }


}
//订阅者
public class Subscriber {
    private static final String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        //声明一个队列,产生一个随机的队列名 如amq.gen-JzTY20BRgKO-HjmUJj0wLg
        String queueName = channel.queueDeclare().getQueue();
        System.out.println("queueName :" +queueName);
        //第三个参数为绑定键, 将队列和交换机绑定
        channel.queueBind(queueName,EXCHANGE_NAME,"");
        System.out.println(" [*] waiting for messages.To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel){
            //处理传送
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"UTF-8");
                System.out.println(" [x] received " + message );

            }
        };
        // 消费者监听队列
        channel.basicConsume(queueName,true,consumer);

    }
}

2.Routing(路由) - direct type

Receiving messages selectively (有选择地接收消息)

这种模式添加了一个路由键,生产者发布消息的时候添加路由键,消费者绑定队列到交换机时添加键值,这样就可以接收到需要接收的消息。与fanout type主要区别是交换机exchange和队列queue绑定的时候添加了路由键。

//发布者
public class RoutePublisher {
    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        // direct类型
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        String[] messages = new String[]{"First message.", "Second message..",
                "Third message...", "Fourth message....", "Fifth message....."};
        String selectKey = "error";
        for(String message : messages){
            //第二个参数为路由键
            channel.basicPublish(EXCHANGE_NAME,selectKey,null,message.getBytes());
            System.out.println("[x] sent " + message);
        }
        channel.close();
        connection.close();
    }
}
// 订阅者
public class RouteSubscriber {
    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");

        String queueName = channel.queueDeclare().getQueue();
        System.out.println("queueName :" +queueName);
        //第三个参数为绑定键,相同的selectKey 才能被接收
        String selectKey = "error";
        channel.queueBind(queueName,EXCHANGE_NAME,selectKey);
        System.out.println(" [*] waiting for messages.To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel){
            //处理传送
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"UTF-8");
                System.out.println(" [x] received " + message );

            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

3.Topics(通配) -topic type

Receiving messages based on a pattern (topics)  基于模式匹配

和路由匹配区别在于,路由键支持模糊匹配规则。符号“#”匹配一个或多个词,“*”仅匹配一个词

//生产者1
public class TopicPublisher {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        // direct类型
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        String[] messages = new String[]{"First message.", "Second message..",
                "Third message...", "Fourth message....", "Fifth message....."};
        String selectKey = "item.insert";
        for(String message : messages){
            //第二个参数为路由键
            channel.basicPublish(EXCHANGE_NAME,selectKey,null,message.getBytes());
            System.out.println("[x] sent " + message);
        }
        String selectKey2 = "item.update";
        for(String message : messages){
            //第二个参数为路由键
            channel.basicPublish(EXCHANGE_NAME,selectKey2,null,message.getBytes());
            System.out.println("[x] sent " + message);
        }
        channel.close();
        connection.close();
    }
}
//消费者1
public class TopicSubscriber {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");

        String queueName = channel.queueDeclare().getQueue();
        System.out.println("queueName :" +queueName);
        //第三个参数为绑定键,相同的selectKey 才能被接收
        String selectKey = "*.insert";
        channel.queueBind(queueName,EXCHANGE_NAME,selectKey);
        System.out.println(" [*] waiting for messages.To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel){
            //处理传送
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"UTF-8");
                System.out.println(" [x] received " + message );

            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}
//消费者2
public class TopicSubscriber2 {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.56.128");
        factory.setUsername("admin");
        factory.setPassword("123456");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");

        String queueName = channel.queueDeclare().getQueue();
        System.out.println("queueName :" +queueName);
        //第三个参数为绑定键,相同的selectKey 才能被接收
        String selectKey = "*.update";
        channel.queueBind(queueName,EXCHANGE_NAME,selectKey);
        System.out.println(" [*] waiting for messages.To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel){
            //处理传送
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"UTF-8");
                System.out.println(" [x] received " + message );

            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

参考:rabbitmq tutorials

         发布订阅模式   路由模式   通配模式

   

猜你喜欢

转载自blog.csdn.net/zl_momomo/article/details/83026838