rabbitmq-交换机的基本使用

之前生产者的消息是发个一个消费者的,如果想多个消费者都收到消息(系统告知所有用户今天促销)就需要使用rabbitmq中交换机(Exchange)功能了。

简示图:

代码:

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 生产者
 * 订阅模式 Publish/Subscribe
 * 通过交换机把消息发送给所有绑定该交换机的队列
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //确认每次只发送一条信息
        channel.basicQos(1);
        //声明一个交换机,该类型交换机对生产者的消息不做任何处理,所有绑定该交换机的队列都会收到生产者的消息
        channel.exchangeDeclare(exchange,"fanout");
        for (int i = 0; i < 50; i++) {
            String msg = "This is test_exchange_fanout:"+i;
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交换机名称
             * routingKey:队列绑定的交换机的key:不指定的时候所有绑定该交换机的队列都能收到消息
             * body: 信息载体
             */
            channel.basicPublish(exchange,"",null,msg.getBytes());
        }
        System.out.println("发送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {
    private static String exchange = "test_exchange_fanout";
    private static String queue = "test_exchange_fanout_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"");
        // 定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
/**
 * 消费者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_fanout";
    private static String queue = "test_exchange_fanout_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"");
        // 定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}

PS:生产者将消息发送到交换机中,哪个消费者的队列绑定了这个交换机,就把消息发送到哪个队列,这样一个消息就会发送个不同的队列让多个消费者接收到了。
fanout:交换机的类型,该类型时所有绑定该交换机的队列都会收到该交换机发出的消息
channel.exchangeDeclare(exchange,"fanout");

QA:若想生产者第一条消息消费者都能接收,第二条消息只让部分消费者接收,应该如何实现?

此时需要使用Exchange的另一种类型:direct,同时队列与交换机使用routingKey进行绑定。

简示图:

此时生产者向exchange推送消息时指定发送给哪个routingKey所绑定的队列。
如指定发送个routingA绑定的队列时两个服务都能收到消息,发送消息给routingC绑定的队列时则只有服务B能收到消息。

/**
 * 生产者
 * 路由模式
 * 交换机的信息发送到指定的key,队列绑定交换机的时候指定的该key才能收到信息
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_direct";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //确认每次只发送一条信息
        //prefetchSize:设置传输过来的消息的大小
        //prefetchCount:一次传输多少消息
        //global:是否是全局消息,true:整个channel都使用该设置,false只应用于当前的customer
        //PS:global:目前设置为false;
        channel.basicQos(1);
        //声明一个交换机,该类型交换机对生产者的消息进行处理,绑定该交换机的队列中存在和交换机发送信息时使用的key的队列才能收到信息
        //交换机名称,交换机类型,是否持久化:消息未完成消费时是否写到磁盘里防止数据丢失
        channel.exchangeDeclare(exchange,"direct",true);
        for (int i = 0; i < 50; i++) {
            String msg = "This is test_exchange_direct:"+i;
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交换机名称
             * routingKey:队列绑定的交换机的key:指定的时候那个队列有这个key哪个队列就会收到交换机的信息
             * body: 信息载体
             */
            //todo routingKey:rabbit==》两个队列都绑定了rabbit所以交换机的信息两个队列都能收到
            channel.basicPublish(exchange,"rabbit",null,msg.getBytes());
            //todo routingKey:monkey==》队列2绑定了monkey所以交换机的信息只有队列2能收到
            //channel.basicPublish(exchange,"monkey",null,msg.getBytes());
        }
        System.out.println("发送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {
    private static String exchange = "test_exchange_direct";
    private static String queue = "test_exchange_direct_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        //rabbit:绑定的路由key
        channel.queueBind(queue,exchange,"rabbit");
        //定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_direct";
    private static String queue = "test_exchange_direct_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"rabbit");
        channel.queueBind(queue,exchange,"cat");
        channel.queueBind(queue,exchange,"dog");
        channel.queueBind(queue,exchange,"bird");
        channel.queueBind(queue,exchange,"monkey");
        // 定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
//将交换机和队列通过routingKey:rabbit进行绑定 ==》队列和交换机之间可绑定多个routingKey
channel.queueBind(queue,exchange,"rabbit");
PS:生产者发送消息时写的routingKey要和消费者绑定的routingKey完全一致,才能接收到消息

QA:每个routingKey都要完全一致,假设服务A是订单模块,服务B是库存模块,那按照上述的方式我们要绑定海量的routingKey才可以,直接增大了开发量和业务的复杂性,如何简化这样的模式呢?
使用Exchangetopic模式,topic主要是实现对routingKey的模糊匹配,从而更加灵活的指定我们的消息发送给哪台服务器。
简示图:

#:表示0个或多个  
例:服务A推送信息的routingKey
order.delete.yesterday  queueB可以接收
order.list  可以接收  queueB可以接收

*:表示一个
warehouse.query   queueA可以接收
warehouse.delete.yesterday    queueA无法接收

服务A发送信息推送至routingA 时,队列queueA和队列queueB都可以接收到信息

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 生产者
 * Topic Exchange
 * 此时队列需要绑定要一个模式上。
 * 符号“#”匹配一个或多个词,符号“*”匹配一个词。
 * 因此“audit.#”能够匹配到“audit.irs.corporate”
 * 但是“audit.*” 只会匹配到“audit.irs”。
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_topic";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //确认每次只发送一条信息
        channel.basicQos(1);
        //声明一个交换机,队列中的key可以和交换机发送信息的key进行匹配时就能收到消息
        channel.exchangeDeclare(exchange,"topic",true);

            String msg = "This is test_exchange_topic";
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交换机名称
             * routingKey:队列绑定的交换机的key:指定的时候那个队列有这个key哪个队列就会收到交换机的信息
             * body: 信息载体
             * */

            //todo routingKey:rabbit==》两个队列都绑定了rabbit所以交换机的信息两个队列都能收到
            channel.basicPublish(exchange,"order.aaa.bbb",null,msg.getBytes());


        System.out.println("发送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {

    private static String exchange = "test_exchange_topic";
    private static String queue = "test_exchange_topic_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"order.list");
        channel.queueBind(queue,exchange,"order.add");
        channel.queueBind(queue,exchange,"order.#");
        channel.queueBind(queue,exchange,"audit.*");
        //定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 消费者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_topic";
    private static String queue = "test_exchange_topic_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //设置让rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"order.del");
        channel.queueBind(queue,exchange,"audit.#");
        channel.queueBind(queue,exchange,"order.*");
        //定义一个消费者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到达 触发这个方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值