RabbitMQ相关术语:
          1.Broker:简单来说就是消息队列服务器实体。
          2.Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
          3.Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
          4.Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
          5.Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
          6.vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
          7.producer:消息生产者,就是投递消息的程序。
          8.consumer:消息消费者,就是接受消息的程序。
          9.channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

RabbitMQ常用发布订阅模式的运行流程:
AMQP模型中,消息在producer中产生,发送到MQ的exchange上,exchange根据配置的路由方式发到相应的Queue上,Queue又将消息发送给consumer,消息从queue到consumer有push和pull两种方式。 消息队列的使用过程大概如下:

1.客户端连接到消息队列服务器,打开一个channel。
          2.客户端声明一个exchange,并设置相关属性。
          3.客户端声明一个queue,并设置相关属性。
          4.客户端使用routing key,在exchange和queue之间建立好绑定关系。
          5.客户端投递消息到exchange。

RabbitMQ教程:

引入maven依赖:

  • <dependency> 
  • <groupId>com.rabbitmq</groupId>
  • <artifactId>amqp-client</artifactId>
  • <version>3.6.5</version>
  • </dependency>

1.hello world!

生产者:

  •  package com.rabbitmq.test.T_helloworld; 
  • import com.rabbitmq.client.Channel;
  • import com.rabbitmq.client.Connection;
  • import com.rabbitmq.test.util.ConnectionUtil;
  • /**
  • * helloworld
  • * @author 
  • */
  • public class Producer {
  • private final static String QUEUE_NAME = "test_queue";
     
  •  public static void main(String[] argv) throws Exception {
  • // 获取到连接以及mq通道
  • Connection connection = ConnectionUtil.getConnection();
  • // 从连接中创建通道
  • Channel channel = connection.createChannel();
  • /*
  • * 声明(创建)队列
  • * 参数1:队列名称
  • * 参数2:为true时server重启队列不会消失
  • * 参数3:队列是否是独占的,如果为true只能被一个connection使用,其他连接建立时会抛出异常
  • * 参数4:队列不再使用时是否自动删除(没有连接,并且没有未处理的消息)
  • * 参数5:建立队列时的其他参数
  • */
  • channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  • // 消息内容
  • String message = "Hello World!";
  • /*
  • * 向server发布一条消息
  • * 参数1:exchange名字,若为空则使用默认的exchange
  • * 参数2:routing key
  • * 参数3:其他的属性
  • * 参数4:消息体
  • * RabbitMQ默认有一个exchange,叫default exchange,它用一个空字符串表示,它是direct exchange类型,
  • * 任何发往这个exchange的消息都会被路由到routing key的名字对应的队列上,如果没有对应的队列,则消息会被丢弃
  • */
  • channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
  • System.out.println(" [生产者] Sent '" + message + "'");
  • //关闭通道和连接
  • channel.close();
  • connection.close();
  • }
  • }

消费者:

  • package com.rabbitmq.test.T_helloworld;
     
  • import com.rabbitmq.client.Channel;
  • import com.rabbitmq.client.Connection;
  • import com.rabbitmq.client.QueueingConsumer;
  • import com.rabbitmq.test.util.ConnectionUtil;
  • public class Consumer {
  • private final static String QUEUE_NAME = "test_queue";
  • public static void main(String[] argv) throws Exception {
  •  // 获取到连接以及mq通道
  • Connection connection = ConnectionUtil.getConnection();
  • // 从连接中创建通道
  • Channel channel = connection.createChannel();
  • // 声明队列(如果你已经明确的知道有这个队列,那么下面这句代码可以注释掉,如果不注释掉的话,也可以理解为消费者必须监听一个队列,如果没有就创建一个)
  • channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  • // 定义队列的消费者
  • QueueingConsumer consumer = new QueueingConsumer(channel);
  • /*
  • * 监听队列
  • * 参数1:队列名称
  • * 参数2:是否发送ack包,不发送ack消息会持续在服务端保存,直到收到ack。 可以通过channel.basicAck手动回复ack
  • * 参数3:消费者
  • */
  • channel.basicConsume(QUEUE_NAME, true, consumer);
  • // 获取消息
  • while (true) {
  • QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  • String message = new String(delivery.getBody());
  • System.out.println(" [消费者] Received '" + message + "'");
  • }
  • }
  • }

2.Work模式
Work普通模式

生产者:

  •  package com.rabbitmq.test.T_work;
  • import com.rabbitmq.client.Channel;
  • import com.rabbitmq.client.Connection;
  • import com.rabbitmq.test.util.ConnectionUtil;
  • /**
  • * work模式
  • * @author lenovo
  • *
  • */
  • public class Producer {
  • private final static String QUEUE_NAME = "test_queue_work";
  • public static void main(String[] argv) throws Exception {
  • // 获取到连接以及mq通道
  • Connection connection = ConnectionUtil.getConnection();
  • Channel channel = connection.createChannel();
  • // 声明队列
  • channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  • for (int i = 0; i < 50; i++) {
  • // 消息内容
  • String message = "" + i;
  • channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
  • System.out.println(" [生产者] Sent '" + message + "'");
  • //发送的消息间隔越来越长
  • Thread.sleep(i * 10);
  • }
  • channel.close();
  • connection.close();
  • }
  • }

消费者1:

  • package com.rabbitmq.test.T_work;
  • import com.rabbitmq.client.Channel;
  • import com.rabbitmq.client.Connection;
  • import com.rabbitmq.client.QueueingConsumer;
  • import com.rabbitmq.test.util.ConnectionUtil;
  • public class Consumer1 {
  • private final static String QUEUE_NAME = "test_queue_work";
  • public static void main(String[] argv) throws Exception {
  • // 获取到连接以及mq通道
  • Connection connection = ConnectionUtil.getConnection();
  • Channel channel = connection.createChannel();
  • // 声明队列
  • channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  • // 同一时刻服务器只会发一条消息给消费者(能者多劳模式)
  • //channel.basicQos(1);
  • // 定义队列的消费者
  • QueueingConsumer consumer = new QueueingConsumer(channel);
  • /*
  • * 监听队列,不自动返回ack包,下面手动返回
  • * 如果不回复,消息不会在服务器删除
  • */
  • channel.basicConsume(QUEUE_NAME, false, consumer);
  • // 获取消息
  • while (true) {
  • QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  • String message = new String(delivery.getBody());
  • System.out.println(" [消费者1] Received '" + message + "'");
  • //休眠
  • Thread.sleep(10);
  • // 手动返回ack包确认状态
  • channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  • //channel.basicReject(); channel.basicNack(); //可以通过这两个函数拒绝消息,可以指定消息在服务器删除还是继续投递给其他消费者
  • }
  • }
  • }

消费者2:

  •  package com.rabbitmq.test.T_work;
  • import com.rabbitmq.client.Channel;
  • import com.rabbitmq.client.Connection;
  • import com.rabbitmq.client.QueueingConsumer;
  • import com.rabbitmq.test.util.ConnectionUtil;
  • public class Consumer2 {
  • private final static String QUEUE_NAME = "test_queue_work";
  • public static void main(String[] argv) throws Exception {
  • // 获取到连接以及mq通道
  • Connection connection = ConnectionUtil.getConnection();
  • Channel channel = connection.createChannel();
  • // 声明队列
  • channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  • // 同一时刻服务器只会发一条消息给消费者(能者多劳模式)
  • //channel.basicQos(1);
  • // 定义队列的消费者
  • QueueingConsumer consumer = new QueueingConsumer(channel);
  • // 监听队列,手动返回完成状态
  • channel.basicConsume(QUEUE_NAME, false, consumer);
  • // 获取消息
  • while (true) {
  • QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  • String message = new String(delivery.getBody());
  • System.out.println(" [消费者2] Received '" + message + "'");
  • // 休眠1秒
  • Thread.sleep(1000);
  • //反馈消息的消费状态
  • channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  • }
  • }
  • }

测试结果:
1、消费者1和消费者2获取到的消息内容是不同的,同一个消息只能被一个消费者获取。
2、消费者1和消费者2获取到的消息的数量是相同的,一个是奇数一个是偶数。

其实,这样是不合理的,应该是消费者1要比消费者2获取到的消息多才对。
Work的能者多劳模式
需要将上面两个消费者的channel.basicQos(1);这行代码的注释打开,再次执行会发现,休眠时间短的消费者执行的任务多
消息的确认
在以上的代码中,已经给出了注释,如何使用自动确认和手动确认,消费者从队列中获取消息,服务端如何知道消息已经被消费呢?
模式1:自动确认
只要消息从队列中获取,无论消费者获取到消息后是否成功消息,都认为是消息已经成功消费。
模式2:手动确认
消费者从队列中获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,如果消费者一直没有反馈,那么该消息将一直处于不可用状态。
如果选用自动确认,在消费者拿走消息执行过程中出现宕机时,消息可能就会丢失!!

3.订阅模式

文章开头有发布订阅的流程介绍

生产者:

  1.  
    package com.rabbitmq.test.T_pubsub;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.test.util.ConnectionUtil;
  6.  
     
  7.  
    /**
  8.  
    * 订阅模式
  9.  
    * @author lenovo
  10.  
    *
  11.  
    */
  12.  
    public class Producer {
  13.  
     
  14.  
    //交换机的名称
  15.  
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
  16.  
     
  17.  
    public static void main(String[] argv) throws Exception {
  18.  
    // 获取到连接以及mq通道
  19.  
    Connection connection = ConnectionUtil.getConnection();
  20.  
    Channel channel = connection.createChannel();
  21.  
     
  22.  
    /*
  23.  
    * 声明exchange(交换机)
  24.  
    * 参数1:交换机名称
  25.  
    * 参数2:交换机类型
  26.  
    * 参数3:交换机持久性,如果为true则服务器重启时不会丢失
  27.  
    * 参数4:交换机在不被使用时是否删除
  28.  
    * 参数5:交换机的其他属性
  29.  
    */
  30.  
    channel.exchangeDeclare(EXCHANGE_NAME, "fanout",true,true,null);
  31.  
     
  32.  
    // 消息内容
  33.  
    String message = "订阅消息";
  34.  
    channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
  35.  
    System.out.println(" [生产者] Sent '" + message + "'");
  36.  
     
  37.  
    channel.close();
  38.  
    connection.close();
  39.  
    }
  40.  
    }

消费者1:

  1.  
    package com.rabbitmq.test.T_pubsub;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.client.QueueingConsumer;
  6.  
    import com.rabbitmq.test.util.ConnectionUtil;
  7.  
     
  8.  
    public class Consumer1 {
  9.  
     
  10.  
    private final static String QUEUE_NAME = "test_queue_exchange_1";
  11.  
     
  12.  
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
  13.  
     
  14.  
    public static void main(String[] argv) throws Exception {
  15.  
     
  16.  
    // 获取到连接以及mq通道
  17.  
    Connection connection = ConnectionUtil.getConnection();
  18.  
    Channel channel = connection.createChannel();
  19.  
     
  20.  
    // 声明队列
  21.  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  22.  
     
  23.  
     
  24.  
    /*
  25.  
    * 绑定队列到交换机(这个交换机的名称一定要和上面的生产者交换机名称相同)
  26.  
    * 参数1:队列的名称
  27.  
    * 参数2:交换机的名称
  28.  
    * 参数3:Routing Key
  29.  
    *
  30.  
    */
  31.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
  32.  
     
  33.  
    // 同一时刻服务器只会发一条消息给消费者
  34.  
    channel.basicQos(1);
  35.  
     
  36.  
    // 定义队列的消费者
  37.  
    QueueingConsumer consumer = new QueueingConsumer(channel);
  38.  
    // 监听队列,手动返回完成
  39.  
    channel.basicConsume(QUEUE_NAME, false, consumer);
  40.  
     
  41.  
    // 获取消息
  42.  
    while (true) {
  43.  
    QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  44.  
    String message = new String(delivery.getBody());
  45.  
    System.out.println(" [消费者1] Received '" + message + "'");
  46.  
    Thread.sleep(10);
  47.  
     
  48.  
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  49.  
    }
  50.  
    }
  51.  
    }

消费者2:

  1.  
    package com.rabbitmq.test.T_pubsub;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.client.QueueingConsumer;
  6.  
    import com.rabbitmq.test.util.ConnectionUtil;
  7.  
     
  8.  
    public class Consumer2 {
  9.  
     
  10.  
    private final static String QUEUE_NAME = "test_queue_exchange_2";
  11.  
     
  12.  
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
  13.  
     
  14.  
    public static void main(String[] argv) throws Exception {
  15.  
     
  16.  
    // 获取到连接以及mq通道
  17.  
    Connection connection = ConnectionUtil.getConnection();
  18.  
    Channel channel = connection.createChannel();
  19.  
     
  20.  
    // 声明队列
  21.  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  22.  
     
  23.  
    // 绑定队列到交换机
  24.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
  25.  
     
  26.  
    // 同一时刻服务器只会发一条消息给消费者
  27.  
    channel.basicQos(1);
  28.  
     
  29.  
    // 定义队列的消费者
  30.  
    QueueingConsumer consumer = new QueueingConsumer(channel);
  31.  
    // 监听队列,手动返回完成
  32.  
    channel.basicConsume(QUEUE_NAME, false, consumer);
  33.  
     
  34.  
    // 获取消息
  35.  
    while (true) {
  36.  
    QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  37.  
    String message = new String(delivery.getBody());
  38.  
    System.out.println(" [消费者2] Received '" + message + "'");
  39.  
    Thread.sleep(10);
  40.  
     
  41.  
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  42.  
    }
  43.  
    }
  44.  
    }

注意:消息发送到没有队列绑定的交换机时,消息将丢失,因为,交换机没有存储消息的能力,消息只能存在在队列中。

Exchange类型
Direct 、Fanout 、Topic  三种类型,RabbitMQ默认有一个exchange,叫default exchange,它用一个空字符串表示,它是direct exchange类型。

下面介绍的路由模式和通配符模式都是属于订阅模式,只不过加入了Routing Key(路由键,文章开头有介绍)。

3.1路由模式

生产者:

  1.  
    package com.rabbitmq.test.T_routing;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.test.util.ConnectionUtil;
  6.  
     
  7.  
    /**
  8.  
    * 路由模式
  9.  
    * @author lenovo
  10.  
    *
  11.  
    */
  12.  
    public class Producer {
  13.  
     
  14.  
    private final static String EXCHANGE_NAME = "test_exchange_direct";
  15.  
     
  16.  
    public static void main(String[] argv) throws Exception {
  17.  
    // 获取到连接以及mq通道
  18.  
    Connection connection = ConnectionUtil.getConnection();
  19.  
    Channel channel = connection.createChannel();
  20.  
     
  21.  
    // 声明exchange
  22.  
    channel.exchangeDeclare(EXCHANGE_NAME, "direct");
  23.  
     
  24.  
    // 消息内容
  25.  
    String message = "这是消息B";
  26.  
    channel.basicPublish(EXCHANGE_NAME, "B", null, message.getBytes());
  27.  
    System.out.println(" [生产者] Sent '" + message + "'");
  28.  
     
  29.  
    channel.close();
  30.  
    connection.close();
  31.  
    }
  32.  
    }

消费者1:

  1.  
    package com.rabbitmq.test.T_routing;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.client.QueueingConsumer;
  6.  
    import com.rabbitmq.test.util.ConnectionUtil;
  7.  
     
  8.  
    public class Consumer1 {
  9.  
     
  10.  
    private final static String QUEUE_NAME = "test_queue_direct_1";
  11.  
     
  12.  
    private final static String EXCHANGE_NAME = "test_exchange_direct";
  13.  
     
  14.  
    public static void main(String[] argv) throws Exception {
  15.  
     
  16.  
    // 获取到连接以及mq通道
  17.  
    Connection connection = ConnectionUtil.getConnection();
  18.  
    Channel channel = connection.createChannel();
  19.  
     
  20.  
    // 声明队列
  21.  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  22.  
     
  23.  
    /*
  24.  
    * 绑定队列到交换机
  25.  
    * 参数1:队列的名称
  26.  
    * 参数2:交换机的名称
  27.  
    * 参数3:routingKey
  28.  
    */
  29.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "A");
  30.  
     
  31.  
    // 同一时刻服务器只会发一条消息给消费者
  32.  
    channel.basicQos(1);
  33.  
     
  34.  
    // 定义队列的消费者
  35.  
    QueueingConsumer consumer = new QueueingConsumer(channel);
  36.  
    // 监听队列,手动返回完成
  37.  
    channel.basicConsume(QUEUE_NAME, false, consumer);
  38.  
     
  39.  
    // 获取消息
  40.  
    while (true) {
  41.  
    QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  42.  
    String message = new String(delivery.getBody());
  43.  
    System.out.println(" [消费者1] Received '" + message + "'");
  44.  
    Thread.sleep(10);
  45.  
     
  46.  
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  47.  
    }
  48.  
    }
  49.  
    }

消费者2:

  1.  
    package com.rabbitmq.test.T_routing;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.client.QueueingConsumer;
  6.  
    import com.rabbitmq.test.util.ConnectionUtil;
  7.  
     
  8.  
    public class Consumer2 {
  9.  
     
  10.  
    private final static String QUEUE_NAME = "test_queue_direct_2";
  11.  
     
  12.  
    private final static String EXCHANGE_NAME = "test_exchange_direct";
  13.  
     
  14.  
    public static void main(String[] argv) throws Exception {
  15.  
     
  16.  
    // 获取到连接以及mq通道
  17.  
    Connection connection = ConnectionUtil.getConnection();
  18.  
    Channel channel = connection.createChannel();
  19.  
     
  20.  
    // 声明队列
  21.  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  22.  
     
  23.  
    // 绑定队列到交换机
  24.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "B");
  25.  
    //如果想让消费者2同时接受routingKey为A 和为B的消息,只要在下面在此添加一个Bing就可以了
  26.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "A");
  27.  
     
  28.  
    // 同一时刻服务器只会发一条消息给消费者
  29.  
    channel.basicQos(1);
  30.  
     
  31.  
    // 定义队列的消费者
  32.  
    QueueingConsumer consumer = new QueueingConsumer(channel);
  33.  
    // 监听队列,手动返回完成
  34.  
    channel.basicConsume(QUEUE_NAME, false, consumer);
  35.  
     
  36.  
    // 获取消息
  37.  
    while (true) {
  38.  
    QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  39.  
    String message = new String(delivery.getBody());
  40.  
    System.out.println(" [消费者2] Received '" + message + "'");
  41.  
    Thread.sleep(10);
  42.  
     
  43.  
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  44.  
    }
  45.  
    }
  46.  
    }

3.2通配符模式
将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”只能匹配一个词。因此“audit.#”能够匹配到“audit.irs”和“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。

生产者:

  1.  
    package com.rabbitmq.test.T_topic;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.test.util.ConnectionUtil;
  6.  
     
  7.  
    /**
  8.  
    * 通配模式
  9.  
    * @author lenovo
  10.  
    *
  11.  
    */
  12.  
    public class Producer {
  13.  
     
  14.  
    private final static String EXCHANGE_NAME = "test_exchange_topic";
  15.  
     
  16.  
    public static void main(String[] argv) throws Exception {
  17.  
    // 获取到连接以及mq通道
  18.  
    Connection connection = ConnectionUtil.getConnection();
  19.  
    Channel channel = connection.createChannel();
  20.  
     
  21.  
    // 声明exchange
  22.  
    channel.exchangeDeclare(EXCHANGE_NAME, "topic");
  23.  
     
  24.  
    // 消息内容 模拟 有人购物下订单
  25.  
    String message = "新增订单:id=101";
  26.  
    channel.basicPublish(EXCHANGE_NAME, "order.insert", null, message.getBytes());
  27.  
    System.out.println(" [生产者] Sent '" + message + "'");
  28.  
     
  29.  
    channel.close();
  30.  
    connection.close();
  31.  
    }
  32.  
     
  33.  
    }

消费者1:

  1.  
    package com.rabbitmq.test.T_topic;
  2.  
     
  3.  
    import com.rabbitmq.client.Channel;
  4.  
    import com.rabbitmq.client.Connection;
  5.  
    import com.rabbitmq.client.QueueingConsumer;
  6.  
    import com.rabbitmq.test.util.ConnectionUtil;
  7.  
     
  8.  
    public class Consumer1 {
  9.  
     
  10.  
    private final static String QUEUE_NAME = "test_queue_topic_1";
  11.  
     
  12.  
    private final static String EXCHANGE_NAME = "test_exchange_topic";
  13.  
     
  14.  
    public static void main(String[] argv) throws Exception {
  15.  
     
  16.  
    // 获取到连接以及mq通道
  17.  
    Connection connection = ConnectionUtil.getConnection();
  18.  
    Channel channel = connection.createChannel();
  19.  
     
  20.  
    // 声明队列
  21.  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
  22.  
     
  23.  
    // 绑定队列到交换机
  24.  
    channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "order.#");
  25.  
     
  26.  
    // 同一时刻服务器只会发一条消息给消费者
  27.  
    channel.basicQos(1);
  28.  
     
  29.  
    // 定义队列的消费者
  30.  
    QueueingConsumer consumer = new QueueingConsumer(channel);
  31.  
    // 监听队列,手动返回完成
  32.  
    channel.basicConsume(QUEUE_NAME, false, consumer);
  33.  
     
  34.  
    // 获取消息
  35.  
    while (true) {
  36.  
    QueueingConsumer.Delivery delivery = consumer.nextDelivery();
  37.  
    String message = new String(delivery.getBody());
  38.  
    System.out.println(" [财务系统] Received '" + message + "'");
  39.  
    Thread.sleep(10);
  40.  
     
  41.  
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  42.  
    }
  43.  
    }
  44.  
    }

消费者2:

    1.  
      package com.rabbitmq.test.T_topic;
    2.  
       
    3.  
      import com.rabbitmq.client.Channel;
    4.  
      import com.rabbitmq.client.Connection;
    5.  
      import com.rabbitmq.client.QueueingConsumer;
    6.  
      import com.rabbitmq.test.util.ConnectionUtil;
    7.  
       
    8.  
      public class Consumer2 {
    9.  
       
    10.  
      private final static String QUEUE_NAME = "test_queue_topic_2";
    11.  
       
    12.  
      private final static String EXCHANGE_NAME = "test_exchange_topic";
    13.  
       
    14.  
      public static void main(String[] argv) throws Exception {
    15.  
       
    16.  
      // 获取到连接以及mq通道
    17.  
      Connection connection = ConnectionUtil.getConnection();
    18.  
      Channel channel = connection.createChannel();
    19.  
       
    20.  
      // 声明队列
    21.  
      channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    22.  
       
    23.  
      // 绑定队列到交换机
    24.  
      channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "order.insert");
    25.  
       
    26.  
      // 同一时刻服务器只会发一条消息给消费者
    27.  
      channel.basicQos(1);
    28.  
       
    29.  
      // 定义队列的消费者
    30.  
      QueueingConsumer consumer = new QueueingConsumer(channel);
    31.  
      // 监听队列,手动返回完成
    32.  
      channel.basicConsume(QUEUE_NAME, false, consumer);
    33.  
       
    34.  
      // 获取消息
    35.  
      while (true) {
    36.  
      QueueingConsumer.Delivery delivery = consumer.nextDelivery();
    37.  
      String message = new String(delivery.getBody());
    38.  
      System.out.println(" [物流系统] Received '" + message + "'");
    39.  
      Thread.sleep(10);
    40.  
       
    41.  
      channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
    42.  
      }
    43.  
      }
    44.  
      }
      原文:http://blog.csdn.net/qq_34021712/article/details/72567801 

RabbitMQ在java中基础使用的更多相关文章

  1. Java中基础类库使用

    Java中基础类库: 在这里我仅仅介绍几种我个人觉得会常常使用的 1:Object类中的Clone机制仅仅是对对象进行浅层次的克隆,假设须要进行深层次的克隆的话那么就要自己写(详细Clone方法请參考 ...

  2. java中基础数据类型的应用

    1.float 与 double float是单精度类型,占用4个字节的存储空间  double是双精度类型,占用8个字节的存储空间  1)当你不声明的时候,默认小数都用double来表示,所以如果要 ...

  3. java中基础类型的初始值,以及一些平时不注意的小知识

    有时候总是卡在一些类型的初始值上,今天闲下来就来自己给自己记录一下. String   a; 如果直接打印会提示未初始化.并且未初始化的a不能比较. 这时,我们定义个person类 person{ S ...

  4. Java中的String、StringBuffer、StringBuilder区别以及Java之StringUtils的用法

    1.String.StringBuffer.StringBuilder的区别 String是Java中基础类型,是immutable类(不可变)的典型实现,利用string进行拼接是会产生过多无用对象 ...

  5. Java ClassLoader基础及加载不同依赖 Jar 中的公共类

    转载自:最新内容及最清晰格式请见 http://www.trinea.cn/android/java-loader-common-class/ 本文主要介绍 ClassLoader 的基础知识,Cla ...

  6. java基础---->java中正则表达式二

    跟正则表达式相关的类有:Pattern.Matcher和String.今天我们就开始Java中正则表达式的学习. Pattern和Matcher的理解 一.正则表达式的使用方法 一般推荐使用的方式如下 ...

  7. Java基础(2):Java中的四个跳转语句总结goto,break,continue,return

    跳转控制语句 Java中的goto是保留字,目前不能使用.虽然没有goto语句可以增强程序的安全性,但是也带来很多不便,比如说,我想在某个循环知道到某一步的时候就结束,现在就做不了这件事情.为了弥补这 ...

  8. Java中实现异常处理的基础知识

    Java中实现异常处理的基础知识 异常 (Exception):发生于程序执行期间,表明出现了一个非法的运行状况.许多JDK中的方法在检测到非法情况时,都会抛出一个异常对象. 例如:数组越界和被0除. ...

  9. Java中的框架基础面试知识

    spring mvc 工作机制(原理): DispatcherServlet主要用作职责调度工作,本身主要用于控制流程 Spring mvc运行原理 1.springmvc将所有的请求都提交给Disp ...

随机推荐

  1. 列出下面几项的URL并解释每部分代表的含义

    列出下面几项的URL并解释每部分代表的含义 a.你的学校 b.你的学校的计算机科学系 c.你的老师的主页

  2. Setup Objective UI with UMG

    创建UI蓝图控件 拖入一个文本框 新建一个Actor,继承自FPSHUD 创建控件,并显示到界面上 新建一个Actor,继承FPSGameMode 将属性里的HUD更改为之前创建的 在世界设置中,将G ...

  3. 自动安装gulpfile中所有依赖的模块

    在gulpfile.js中定义任务的时候,需要引用不同的模块,这些模块需要使用 npm install --save-dev 命令进行安装,非常的繁琐.可以使用一个名为gulpfile-install ...

  4. linux系统 之 curl命令

    1,curl命令 在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具.它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工 ...

  5. 基于keepalived搭建MySQL热机集群

    背景 MySQL的高可用方案一般有如下几种: keepalived+双主,MHA,MMM,Heartbeat+DRBD,PXC,Galera Cluster 比较常用的是keepalived+双主,M ...

  6. QML 从入门到放弃 第二卷

    第二卷如何更快速的放弃,注重的是C++和QML的交互 <1>记事本.. (1) 先测试下不在QML创建C++对象,仅仅在main.cpp添加一个属性函数供调用. 注意只使用槽函数来做到. ...

  7. Latex 问题解决

    1. 当bib文件中包含待引用的参考文献,并且在tex中正常通过\cite{}引用,却依然提示citation undefined,pdf中显示问号时,怎么解决报错. 解决:删除根目录下的  .bbl ...

  8. PHP操作MongoDB 数据库

    最近有个项目,需要用php操作mongoDb数据,整理如下 1,连接MongoDB数据库 $conn = new Mongo(); 其他链接方式 //$conn=new Mongo(); #连接本地主 ...

  9. 解决python发送multipart/form-data请求上传文件的问题

    服务器接收文件时,有时会使用表单接收的方式,这意味着我们需要使用Python的requests上传表单数据和文件. 常用的方式一般如下: data = { 'name': 'nginx' } file ...

  10. ansible笔记(4):常用模块之文件操作

    前文中,我们已经介绍了怎样使用模块,而且我们知道,ansible有很多模块,每个模块都有自己的功能,"模块"涉及到的方向比较多,所以对于个人来说,并没有必要了解所有的模块,我们只需 ...