最近学习RabbitMQ的使用方式,记录下来,方便以后使用,也方便和大家共享,相互交流。

RabbitMQ的六种工作模式:

1、Work queues
2、Publish/subscribe
3、Routing
4、Topics
5、Header 模式
6、RPC

一、Work queues

多个消费端消费同一个队列中的消息,队列采用轮询的方式将消息是平均发送给消费者;

特点:

1、一条消息只会被一个消费端接收;

2、队列采用轮询的方式将消息是平均发送给消费者的;

3、消费者在处理完某条消息后,才会收到下一条消息

生产端:

1、声明队列

2、创建连接

3、创建通道

4、通道声明队列

5、制定消息

6、发送消息,使用默认交换机

消费端:

1、声明队列

2、创建连接

3、创建通道

4、通道声明队列

5、重写消息消费方法

6、执行消息方法

新建两个maven工程,生产消息的生产端,消费消息的消费端;

pom.xml文件中依赖坐标如下:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-logging</artifactId>
  5. <version>2.1.0.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.rabbitmq</groupId>
  9. <artifactId>amqp-client</artifactId>
  10. <version>5.7.0</version>
  11. </dependency>
  12. </dependencies>

生产端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.BuiltinExchangeType;
  4. import com.rabbitmq.client.Channel;
  5. import com.rabbitmq.client.Connection;
  6. import com.rabbitmq.client.ConnectionFactory;
  7.  
  8. import java.io.IOException;
  9. import java.util.concurrent.TimeoutException;
  10. /*
  11. 1、声明队列
  12. 2、创建连接
  13. 3、创建通道
  14. 4、通道声明队列
  15. 5、制定消息
  16. 6、发送消息,使用默认交换机
  17. */
  18. public class Producer02 {
  19. //声明队列
  20. private static final String QUEUE ="queue";
  21. public static void main(String[] args) {
  22. Connection connection = null;
  23. Channel channel = null;
  24. try {
  25. ConnectionFactory connectionFactory = new ConnectionFactory();
  26. connectionFactory.setHost("127.0.0.1");//mq服务ip地址
  27. connectionFactory.setPort(5672);//mq client连接端口
  28. connectionFactory.setUsername("guest");//mq登录用户名
  29. connectionFactory.setPassword("guest");//mq登录密码
  30. connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
  31. //创建与RabbitMQ服务的TCP连接
  32. connection = connectionFactory.newConnection();
  33. //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
  34. channel = connection.createChannel();
  35.  
  36. //通道绑定队列
  37. /**
  38. * 声明队列,如果Rabbit中没有此队列将自动创建
  39. * param1:队列名称
  40. * param2:是否持久化
  41. * param3:队列是否独占此连接
  42. * param4:队列不再使用时是否自动删除此队列
  43. * param5:队列参数
  44. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  45. *
  46. */
  47. channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列
  48.  
  49. for(int i = 0;i<10;i++){
  50. String message = new String("mq 发送消息。。。");
  51. /**
  52.              * 消息发布方法
  53.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  54.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  55.              * param3:消息包含的属性
  56.              * param4:消息体
  57.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  58.  * 默认的交换机,routingKey等于队列名称
  59. */
  60. //String exchange, String routingKey, BasicProperties props, byte[] body
  61. channel.basicPublish("",QUEUE,null,message.getBytes("utf-8"));
  62. System.out.println("mq消息发送成功!");
  63. }
  64. } catch (Exception e) {
  65. e.printStackTrace();
  66. } finally {
  67. try {
  68. channel.close();
  69. } catch (IOException e) {
  70. e.printStackTrace();
  71. } catch (TimeoutException e) {
  72. e.printStackTrace();
  73. }
  74. try {
  75. connection.close();
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. }
  81. }

消费端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7. /*
  8. 1、声明队列
  9. 2、创建连接
  10. 3、创建通道
  11. 4、通道声明队列
  12. 5、重写消息消费方法
  13. 6、执行消息方法
  14. */
  15. public class Consumer02 {
  16. private static final String QUEUE ="queue";
  17. public static void main(String[] args) {
  18. Connection connection = null;
  19. Channel channel = null;
  20. try {
  21. ConnectionFactory connectionFactory = new ConnectionFactory();
  22. connectionFactory.setHost("127.0.0.1");
  23. connectionFactory.setPort(5672);
  24. connection = connectionFactory.newConnection();
  25. channel = connection.createChannel();
  26. //通道绑定队列
  27. /**
  28. * 声明队列,如果Rabbit中没有此队列将自动创建
  29. * param1:队列名称
  30. * param2:是否持久化
  31. * param3:队列是否独占此连接
  32. * param4:队列不再使用时是否自动删除此队列
  33. * param5:队列参数
  34. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  35. *
  36. */
  37. channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列
  38.  
  39. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  40. DefaultConsumer consumer = new DefaultConsumer(channel) {
  41. /**
  42.              * 消费者接收消息调用此方法
  43.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  44.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  45. (收到消息失败后是否需要重新发送)
  46.              * @param properties
  47.              * @param body
  48.              * @throws IOException
  49. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  50. */
  51. @Override
  52. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  53. //交换机
  54. String exchange = envelope.getExchange();
  55. //路由key
  56. String routingKey = envelope.getRoutingKey();
  57. envelope.getDeliveryTag();
  58. String msg = new String(body,"utf-8");
  59. System.out.println("mq收到的消息是:"+msg );
  60. }
  61.  
  62. };
  63. System.out.println("消费者启动成功!");
  64. channel.basicConsume(QUEUE,true,consumer);
  65.  
  66. } catch (IOException e) {
  67. e.printStackTrace();
  68. } catch (TimeoutException e) {
  69. e.printStackTrace();
  70. }
  71. }
  72. }

生产端启动后,控制台打印信息如下:

RabbitMQ中的已有消息:

queue中的消息正是生产端发送的消息:

二、Publish/subscribe 模式

这种模式又称为发布订阅模式,相对于Work queues模式,该模式多了一个交换机,生产端先把消息发送到交换机,再由交换机把消息发送到绑定的队列中,每个绑定的队列都能收到由生产端发送的消息。

发布订阅模式:

1、每个消费者监听自己的队列;

2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收
到消息

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机

7、制定消息

8、发送消息

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机

7、重写消息消费方法

8、执行消息方法

Publish/subscribe 模式绑定两个消费端,因此需要有两个消费端,一个邮件消费端,一个短信消费端;

生产端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.BuiltinExchangeType;
  4. import com.rabbitmq.client.Channel;
  5. import com.rabbitmq.client.Connection;
  6. import com.rabbitmq.client.ConnectionFactory;
  7.  
  8. import java.io.IOException;
  9. import java.util.concurrent.TimeoutException;
  10.  
  11. public class Producer01 {
  12. //声明两个队列和一个交换机
  13. //Publish/subscribe发布订阅模式
  14. private static final String QUEUE_EMAIL ="queueEmail";
  15. private static final String QUEUE_SMS ="queueSms";
  16. private static final String EXCHANGE = "messageChange";
  17. public static void main(String[] args) {
  18. Connection connection = null;
  19. Channel channel = null;
  20. try {
  21. ConnectionFactory connectionFactory = new ConnectionFactory();
  22. connectionFactory.setHost("127.0.0.1");//mq服务ip地址
  23. connectionFactory.setPort(5672);//mq client连接端口
  24. connectionFactory.setUsername("guest");//mq登录用户名
  25. connectionFactory.setPassword("guest");//mq登录密码
  26. connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
  27. //创建与RabbitMQ服务的TCP连接
  28. connection = connectionFactory.newConnection();
  29. //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
  30. channel = connection.createChannel();
  31. //通道绑定交换机
  32. /**
  33.              * 参数明细
  34.              * 1、交换机名称
  35.              * 2、交换机类型,fanout、topic、direct、headers
  36.              */
  37. //Publish/subscribe发布订阅模式
  38. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
  39. //通道绑定队列
  40. /**
  41. * 声明队列,如果Rabbit中没有此队列将自动创建
  42. * param1:队列名称
  43. * param2:是否持久化
  44. * param3:队列是否独占此连接
  45. * param4:队列不再使用时是否自动删除此队列
  46. * param5:队列参数
  47. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  48. *
  49. */
  50. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  51. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  52. //交换机和队列绑定
  53. /**
  54. * 参数明细
  55. * 1、队列名称
  56. * 2、交换机名称
  57. * 3、路由key
  58. */
  59. //Publish/subscribe发布订阅模式
  60. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");
  61. channel.queueBind(QUEUE_SMS,EXCHANGE,"");
  62. for(int i = 0;i<10;i++){
  63. String message = new String("mq 发送消息。。。");
  64. /**
  65.              * 消息发布方法
  66.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  67.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  68.              * param3:消息包含的属性
  69.              * param4:消息体
  70.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  71.  * 默认的交换机,routingKey等于队列名称
  72. */
  73. //String exchange, String routingKey, BasicProperties props, byte[] body
  74. //Publish/subscribe发布订阅模式
  75. channel.basicPublish(EXCHANGE,"",null,message.getBytes());
  76. System.out.println("mq消息发送成功!");
  77. }
  78. } catch (Exception e) {
  79. e.printStackTrace();
  80. } finally {
  81. try {
  82. channel.close();
  83. } catch (IOException e) {
  84. e.printStackTrace();
  85. } catch (TimeoutException e) {
  86. e.printStackTrace();
  87. }
  88. try {
  89. connection.close();
  90. } catch (IOException e) {
  91. e.printStackTrace();
  92. }
  93. }
  94. }
  95. }

邮件消费端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer01 {
  9. //Publish/subscribe发布订阅模式
  10. private static final String QUEUE_EMAIL ="queueEmail";
  11. private static final String EXCHANGE = "messageChange";
  12. public static void main(String[] args) {
  13. Connection connection = null;
  14. Channel channel = null;
  15. try {
  16. ConnectionFactory connectionFactory = new ConnectionFactory();
  17. connectionFactory.setHost("127.0.0.1");
  18. connectionFactory.setPort(5672);
  19. connection = connectionFactory.newConnection();
  20. channel = connection.createChannel();
  21. //通道绑定交换机
  22. /**
  23.              * 参数明细
  24.              * 1、交换机名称
  25.              * 2、交换机类型,fanout、topic、direct、headers
  26.              */
  27. //Publish/subscribe发布订阅模式
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. */
  48. //Publish/subscribe发布订阅模式
  49. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");
  50. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  51. DefaultConsumer consumer = new DefaultConsumer(channel) {
  52. /**
  53.              * 消费者接收消息调用此方法
  54.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  55.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  56. (收到消息失败后是否需要重新发送)
  57.              * @param properties
  58.              * @param body
  59.              * @throws IOException
  60. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  61. */
  62. @Override
  63. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  64. //交换机
  65. String exchange = envelope.getExchange();
  66. //路由key
  67. String routingKey = envelope.getRoutingKey();
  68. envelope.getDeliveryTag();
  69. String msg = new String(body,"utf-8");
  70. System.out.println("mq收到的消息是:"+msg );
  71. }
  72. };
  73. System.out.println("消费者启动成功!");
  74. channel.basicConsume(QUEUE_EMAIL,true,consumer);
  75. } catch (IOException e) {
  76. e.printStackTrace();
  77. } catch (TimeoutException e) {
  78. e.printStackTrace();
  79. }
  80. }
  81. }

短信消费端的代码如下:

  1. package xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer01 {
  9. //Publish/subscribe发布订阅模式
  10. private static final String QUEUE_SMS ="queueSms";
  11. private static final String EXCHANGE = "messageChange";
  12. public static void main(String[] args) {
  13. Connection connection = null;
  14. Channel channel = null;
  15. try {
  16. ConnectionFactory connectionFactory = new ConnectionFactory();
  17. connectionFactory.setHost("127.0.0.1");
  18. connectionFactory.setPort(5672);
  19. connection = connectionFactory.newConnection();
  20. channel = connection.createChannel();
  21. //通道绑定交换机
  22. /**
  23.              * 参数明细
  24.              * 1、交换机名称
  25.              * 2、交换机类型,fanout、topic、direct、headers
  26.              */
  27. //Publish/subscribe发布订阅模式
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. */
  48. //Publish/subscribe发布订阅模式
  49. channel.queueBind(QUEUE_SMS,EXCHANGE,"");
  50. DefaultConsumer consumer = new DefaultConsumer(channel) {
  51. /**
  52.              * 消费者接收消息调用此方法
  53.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  54.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  55. (收到消息失败后是否需要重新发送)
  56.              * @param properties
  57.              * @param body
  58.              * @throws IOException
  59. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  60. */
  61. @Override
  62. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  63. //交换机
  64. String exchange = envelope.getExchange();
  65. //路由key
  66. String routingKey = envelope.getRoutingKey();
  67. envelope.getDeliveryTag();
  68. String msg = new String(body,"utf-8");
  69. System.out.println("mq收到的消息是:"+msg );
  70. }
  71.  
  72. };
  73. System.out.println("消费者启动成功!");
  74. channel.basicConsume(QUEUE_SMS,true,consumer);
  75.  
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. } catch (TimeoutException e) {
  79. e.printStackTrace();
  80. }
  81. }
  82. }

三、Routing 路由模式

Routing 模式又称路由模式,该种模式除了要绑定交换机外,发消息的时候还要制定routing key,即路由key,队列通过通道绑定交换机的时候,需要指定自己的routing key,这样,生产端发送消息的时候也会指定routing key,通过routing key就可以把相应的消息发送到绑定相应routing key的队列中去。

路由模式:

1、每个消费者监听自己的队列,并且设置routingkey;
2、生产者将消息发给交换机,由交换机根据routingkey来转发消息到指定的队列;

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定该队列的routingkey

7、制定消息

8、发送消息并指定routingkey

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定routingkey

7、重写消息消费方法

8、执行消息方法

按照假设的应用场景,同样,Routing 路由模式也是一个生产端,两个消费端,所不同的是,声明交换机的类型不同,队列绑定交换机的时候需要指定Routing key,发送消息的时候也需要指定Routing key,这样根据Routing key就能把相应的消息发送到相应的队列中去。

生产端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.BuiltinExchangeType;
  4. import com.rabbitmq.client.Channel;
  5. import com.rabbitmq.client.Connection;
  6. import com.rabbitmq.client.ConnectionFactory;
  7.  
  8. import java.io.IOException;
  9. import java.util.concurrent.TimeoutException;
  10.  
  11. public class Producer03 {
  12. //声明两个队列和一个交换机
  13. //Routing 路由模式
  14. private static final String QUEUE_EMAIL ="queueEmail";
  15. private static final String QUEUE_SMS ="queueSms";
  16. private static final String EXCHANGE = "messageChange";
  17. public static void main(String[] args) {
  18. Connection connection = null;
  19. Channel channel = null;
  20. try {
  21. ConnectionFactory connectionFactory = new ConnectionFactory();
  22. connectionFactory.setHost("127.0.0.1");//mq服务ip地址
  23. connectionFactory.setPort(5672);//mq client连接端口
  24. connectionFactory.setUsername("guest");//mq登录用户名
  25. connectionFactory.setPassword("guest");//mq登录密码
  26. connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
  27. //创建与RabbitMQ服务的TCP连接
  28. connection = connectionFactory.newConnection();
  29. //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
  30. channel = connection.createChannel();
  31. //通道绑定交换机
  32. /**
  33.              * 参数明细
  34.              * 1、交换机名称
  35.              * 2、交换机类型,fanout、topic、direct、headers
  36.              */
  37. //Routing 路由模式
  38. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
  39. //通道绑定队列
  40. /**
  41. * 声明队列,如果Rabbit中没有此队列将自动创建
  42. * param1:队列名称
  43. * param2:是否持久化
  44. * param3:队列是否独占此连接
  45. * param4:队列不再使用时是否自动删除此队列
  46. * param5:队列参数
  47. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  48. *
  49. */
  50. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  51. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  52. //交换机和队列绑定
  53. /**
  54. * 参数明细
  55. * 1、队列名称
  56. * 2、交换机名称
  57. * 3、路由key
  58. */
  59. //Routing 路由模式
  60. channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);
  61. channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);
  62. //给email队列发消息
  63. for(int i = 0;i<10;i++){
  64. String message = new String("mq 发送email消息。。。");
  65. /**
  66.              * 消息发布方法
  67.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  68.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  69.              * param3:消息包含的属性
  70.              * param4:消息体
  71.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  72.  * 默认的交换机,routingKey等于队列名称
  73. */
  74. //String exchange, String routingKey, BasicProperties props, byte[] body
  75. //Routing 路由模式
  76. channel.basicPublish(EXCHANGE,QUEUE_EMAIL,null,message.getBytes());
  77. System.out.println("mq消息发送成功!");
  78. }
  79. //给sms队列发消息
  80. for(int i = 0;i<10;i++){
  81. String message = new String("mq 发送sms消息。。。");
  82. /**
  83.              * 消息发布方法
  84.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  85.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  86.              * param3:消息包含的属性
  87.              * param4:消息体
  88.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  89.  * 默认的交换机,routingKey等于队列名称
  90. */
  91. //String exchange, String routingKey, BasicProperties props, byte[] body
  92. //Routing 路由模式
  93. channel.basicPublish(EXCHANGE,QUEUE_SMS,null,message.getBytes());
  94. System.out.println("mq消息发送成功!");
  95. }
  96. } catch (Exception e) {
  97. e.printStackTrace();
  98. } finally {
  99. try {
  100. channel.close();
  101. } catch (IOException e) {
  102. e.printStackTrace();
  103. } catch (TimeoutException e) {
  104. e.printStackTrace();
  105. }
  106. try {
  107. connection.close();
  108. } catch (IOException e) {
  109. e.printStackTrace();
  110. }
  111. }
  112. }
  113. }

邮件消费端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer03 {
  9. //Routing 路由模式
  10. private static final String QUEUE_EMAIL ="queueEmail";
  11. private static final String EXCHANGE = "messageChange";
  12. public static void main(String[] args) {
  13. Connection connection = null;
  14. Channel channel = null;
  15. try {
  16. ConnectionFactory connectionFactory = new ConnectionFactory();
  17. connectionFactory.setHost("127.0.0.1");
  18. connectionFactory.setPort(5672);
  19. connection = connectionFactory.newConnection();
  20. channel = connection.createChannel();
  21. //通道绑定交换机
  22. /**
  23.              * 参数明细
  24.              * 1、交换机名称
  25.              * 2、交换机类型,fanout、topic、direct、headers
  26.              */
  27. //Routing 路由模式
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. */
  48. //Routing 路由模式
  49. channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);
  50. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  51. DefaultConsumer consumer = new DefaultConsumer(channel) {
  52. /**
  53.              * 消费者接收消息调用此方法
  54.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  55.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  56. (收到消息失败后是否需要重新发送)
  57.              * @param properties
  58.              * @param body
  59.              * @throws IOException
  60. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  61. */
  62. @Override
  63. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  64. //交换机
  65. String exchange = envelope.getExchange();
  66. //路由key
  67. String routingKey = envelope.getRoutingKey();
  68. envelope.getDeliveryTag();
  69. String msg = new String(body,"utf-8");
  70. System.out.println("mq收到的消息是:"+msg );
  71. }
  72.  
  73. };
  74. System.out.println("消费者启动成功!");
  75. channel.basicConsume(QUEUE_EMAIL,true,consumer);
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. } catch (TimeoutException e) {
  79. e.printStackTrace();
  80. }
  81. }
  82. }

短信消费端的代码如下:

  1. package xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer03 {
  9. //Routing 路由模式
  10. private static final String QUEUE_SMS ="queueSms";
  11. private static final String EXCHANGE = "messageChange";
  12. public static void main(String[] args) {
  13. Connection connection = null;
  14. Channel channel = null;
  15. try {
  16. ConnectionFactory connectionFactory = new ConnectionFactory();
  17. connectionFactory.setHost("127.0.0.1");
  18. connectionFactory.setPort(5672);
  19. connection = connectionFactory.newConnection();
  20. channel = connection.createChannel();
  21. //通道绑定交换机
  22. /**
  23.              * 参数明细
  24.              * 1、交换机名称
  25.              * 2、交换机类型,fanout、topic、direct、headers
  26.              */
  27. //Routing 路由模式
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. */
  48. //Routing 路由模式
  49. channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);
  50. DefaultConsumer consumer = new DefaultConsumer(channel) {
  51. /**
  52.              * 消费者接收消息调用此方法
  53.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  54.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  55. (收到消息失败后是否需要重新发送)
  56.              * @param properties
  57.              * @param body
  58.              * @throws IOException
  59. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  60. */
  61. @Override
  62. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  63. //交换机
  64. String exchange = envelope.getExchange();
  65. //路由key
  66. String routingKey = envelope.getRoutingKey();
  67. envelope.getDeliveryTag();
  68. String msg = new String(body,"utf-8");
  69. System.out.println("mq收到的消息是:"+msg );
  70. }
  71. };
  72. System.out.println("消费者启动成功!");
  73. channel.basicConsume(QUEUE_SMS,true,consumer);
  74. } catch (IOException e) {
  75. e.printStackTrace();
  76. } catch (TimeoutException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. }

四、Topics 模式

Topics 模式和Routing 路由模式最大的区别就是,Topics 模式发送消息和消费消息的时候是通过通配符去进行匹配的。

路由模式:

1、每个消费者监听自己的队列,并且设置带统配符的routingkey

2、生产者将消息发给broker,由交换机根据routingkey来转发消息到指定的队列

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定该队列的routingkey(通配符)

7、制定消息

8、发送消息并指定routingkey(通配符)

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定routingkey(通配符)

7、重写消息消费方法

8、执行消息方法

按照假设的应用场景,Topics 模式也是一个生产端,两个消费端,生产端队列绑定交换机的时候,需要指定的routingkey是通配符,发送消息的时候绑定的routingkey也是通配符,消费端队列绑定交换机的时候routingkey也是通配符,这样就能根据通配符匹配到消息了。

生产端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.BuiltinExchangeType;
  4. import com.rabbitmq.client.Channel;
  5. import com.rabbitmq.client.Connection;
  6. import com.rabbitmq.client.ConnectionFactory;
  7.  
  8. import java.io.IOException;
  9. import java.util.concurrent.TimeoutException;
  10.  
  11. public class Producer04 {
  12. //声明两个队列和一个交换机
  13. //Topics 模式
  14. private static final String QUEUE_EMAIL ="queueEmail";
  15. private static final String QUEUE_SMS ="queueSms";
  16. private static final String EXCHANGE = "messageChange";
  17. public static void main(String[] args) {
  18. Connection connection = null;
  19. Channel channel = null;
  20. try {
  21. ConnectionFactory connectionFactory = new ConnectionFactory();
  22. connectionFactory.setHost("127.0.0.1");//mq服务ip地址
  23. connectionFactory.setPort(5672);//mq client连接端口
  24. connectionFactory.setUsername("guest");//mq登录用户名
  25. connectionFactory.setPassword("guest");//mq登录密码
  26. connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
  27. //创建与RabbitMQ服务的TCP连接
  28. connection = connectionFactory.newConnection();
  29. //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
  30. channel = connection.createChannel();
  31. //通道绑定交换机
  32. /**
  33.              * 参数明细
  34.              * 1、交换机名称
  35.              * 2、交换机类型,fanout、topic、direct、headers
  36.              */
  37. //Topics 模式
  38. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
  39. //通道绑定队列
  40. /**
  41. * 声明队列,如果Rabbit中没有此队列将自动创建
  42. * param1:队列名称
  43. * param2:是否持久化
  44. * param3:队列是否独占此连接
  45. * param4:队列不再使用时是否自动删除此队列
  46. * param5:队列参数
  47. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  48. *
  49. */
  50. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  51. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  52. //交换机和队列绑定
  53. /**
  54. * 参数明细
  55. * 1、队列名称
  56. * 2、交换机名称
  57. * 3、路由key
  58. */
  59. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");
  60. channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");
  61. //给email队列发消息
  62. for(int i = 0;i<10;i++){
  63. String message = new String("mq 发送email消息。。。");
  64. /**
  65.              * 消息发布方法
  66.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  67.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  68.              * param3:消息包含的属性
  69.              * param4:消息体
  70.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  71.  * 默认的交换机,routingKey等于队列名称
  72. */
  73. //String exchange, String routingKey, BasicProperties props, byte[] body
  74. channel.basicPublish(EXCHANGE,"inform.email",null,message.getBytes());
  75. System.out.println("mq email 消息发送成功!");
  76. }
  77. //给sms队列发消息
  78. for(int i = 0;i<10;i++){
  79. String message = new String("mq 发送sms消息。。。");
  80. /**
  81.              * 消息发布方法
  82.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  83.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  84.              * param3:消息包含的属性
  85.              * param4:消息体
  86.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  87.  * 默认的交换机,routingKey等于队列名称
  88. */
  89. //String exchange, String routingKey, BasicProperties props, byte[] body
  90. channel.basicPublish(EXCHANGE,"inform.sms",null,message.getBytes());
  91. System.out.println("mq sms 消息发送成功!");
  92. }
  93. //给email和sms队列发消息
  94. for(int i = 0;i<10;i++){
  95. String message = new String("mq 发送email sms消息。。。");
  96. /**
  97.              * 消息发布方法
  98.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  99.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  100.              * param3:消息包含的属性
  101.              * param4:消息体
  102.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  103.  * 默认的交换机,routingKey等于队列名称
  104. */
  105. //String exchange, String routingKey, BasicProperties props, byte[] body
  106. channel.basicPublish(EXCHANGE,"inform.email.sms",null,message.getBytes());
  107. System.out.println("mq email sms 消息发送成功!");
  108. }
  109. } catch (Exception e) {
  110. e.printStackTrace();
  111. } finally {
  112. try {
  113. channel.close();
  114. } catch (IOException e) {
  115. e.printStackTrace();
  116. } catch (TimeoutException e) {
  117. e.printStackTrace();
  118. }
  119. try {
  120. connection.close();
  121. } catch (IOException e) {
  122. e.printStackTrace();
  123. }
  124. }
  125. }
  126. }

邮件消费端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer04 {
  9. private static final String QUEUE_EMAIL ="queueEmail";
  10. private static final String EXCHANGE = "messageChange";
  11. public static void main(String[] args) {
  12. Connection connection = null;
  13. Channel channel = null;
  14. try {
  15. ConnectionFactory connectionFactory = new ConnectionFactory();
  16. connectionFactory.setHost("127.0.0.1");
  17. connectionFactory.setPort(5672);
  18. connection = connectionFactory.newConnection();
  19. channel = connection.createChannel();
  20. //通道绑定交换机
  21. /**
  22.              * 参数明细
  23.              * 1、交换机名称
  24.              * 2、交换机类型,fanout、topic、direct、headers
  25.              */
  26. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
  27. //通道绑定队列
  28. /**
  29. * 声明队列,如果Rabbit中没有此队列将自动创建
  30. * param1:队列名称
  31. * param2:是否持久化
  32. * param3:队列是否独占此连接
  33. * param4:队列不再使用时是否自动删除此队列
  34. * param5:队列参数
  35. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  36. *
  37. */
  38. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  39. //交换机和队列绑定
  40. /**
  41. * 参数明细
  42. * 1、队列名称
  43. * 2、交换机名称
  44. * 3、路由key
  45. */
  46. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");
  47. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  48. DefaultConsumer consumer = new DefaultConsumer(channel) {
  49. /**
  50.              * 消费者接收消息调用此方法
  51.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  52.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  53. (收到消息失败后是否需要重新发送)
  54.              * @param properties
  55.              * @param body
  56.              * @throws IOException
  57. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  58. */
  59. @Override
  60. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  61. //交换机
  62. String exchange = envelope.getExchange();
  63. //路由key
  64. String routingKey = envelope.getRoutingKey();
  65. envelope.getDeliveryTag();
  66. String msg = new String(body,"utf-8");
  67. System.out.println("mq收到的消息是:"+msg );
  68. }
  69.  
  70. };
  71. System.out.println("消费者启动成功!");
  72. channel.basicConsume(QUEUE_EMAIL,true,consumer);
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. } catch (TimeoutException e) {
  76. e.printStackTrace();
  77. }
  78. }
  79. }

短信消费端的代码如下:

  1. package xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.concurrent.TimeoutException;
  7.  
  8. public class Consumer04 {
  9. private static final String QUEUE_SMS ="queueSms";
  10. private static final String EXCHANGE = "messageChange";
  11. public static void main(String[] args) {
  12. Connection connection = null;
  13. Channel channel = null;
  14. try {
  15. ConnectionFactory connectionFactory = new ConnectionFactory();
  16. connectionFactory.setHost("127.0.0.1");
  17. connectionFactory.setPort(5672);
  18. connection = connectionFactory.newConnection();
  19. channel = connection.createChannel();
  20. //通道绑定交换机
  21. /**
  22.              * 参数明细
  23.              * 1、交换机名称
  24.              * 2、交换机类型,fanout、topic、direct、headers
  25.              */
  26. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
  27. //通道绑定队列
  28. /**
  29. * 声明队列,如果Rabbit中没有此队列将自动创建
  30. * param1:队列名称
  31. * param2:是否持久化
  32. * param3:队列是否独占此连接
  33. * param4:队列不再使用时是否自动删除此队列
  34. * param5:队列参数
  35. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  36. *
  37. */
  38. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列
  39. //交换机和队列绑定
  40. /**
  41. * 参数明细
  42. * 1、队列名称
  43. * 2、交换机名称
  44. * 3、路由key
  45. */
  46. channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");
  47. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  48. DefaultConsumer consumer = new DefaultConsumer(channel) {
  49. /**
  50.              * 消费者接收消息调用此方法
  51.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  52.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  53. (收到消息失败后是否需要重新发送)
  54.              * @param properties
  55.              * @param body
  56.              * @throws IOException
  57. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  58. */
  59. @Override
  60. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  61. //交换机
  62. String exchange = envelope.getExchange();
  63. //路由key
  64. String routingKey = envelope.getRoutingKey();
  65. envelope.getDeliveryTag();
  66. String msg = new String(body,"utf-8");
  67. System.out.println("mq收到的消息是:"+msg );
  68. }
  69.  
  70. };
  71. System.out.println("消费者启动成功!");
  72. channel.basicConsume(QUEUE_SMS,true,consumer);
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. } catch (TimeoutException e) {
  76. e.printStackTrace();
  77. }
  78. }
  79. }

由于生产端同时发送了email的消息(10条),sms的消息(10条),email和sms同时收到的消息(10条),所以每个消费端都应收到各自的10条消息,加上同时都能收到的10条消息,每个消费端应该收到20条消息;

生产端控制台打印:

邮件消费端控制台打印:

短信消费端的控制台打印:

生产端执行后,RabbitMQ上的消息队列情况:

两个消费端执行完后,RabbitMQ上的消息队列情况:

五、Header 模式

header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配队列。

案例:

根据用户的通知设置去通知用户,设置接收Email的用户只接收Email,设置接收sms的用户只接收sms,设置两种通知类型都接收的则两种通知都有效。

根据假设使用场景,需要一个生产端,两个消费端,不同的是,生产端声明交换机时,交换机的类型不同,是headers类型,生产端队列绑定交换机时,不使用routingkey,而是使用header中的 key/value(键值对)匹配队列,发送消息时也是使用header中的 key/value(键值对)匹配队列。

消费端同样是声明交换机时,交换机的类型不同,是headers类型,消费端队列绑定交换机时,不使用routingkey,而是使用header中的 key/value(键值对)匹配队列,消费消息时也是使用header中的 key/value(键值对)匹配队列。

生产端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.Hashtable;
  7. import java.util.Map;
  8. import java.util.concurrent.TimeoutException;
  9.  
  10. public class Producer05 {
  11. //声明两个队列和一个交换机
  12. //Header 模式
  13. private static final String QUEUE_EMAIL ="queueEmail";
  14. private static final String QUEUE_SMS ="queueSms";
  15. private static final String EXCHANGE = "messageChange";
  16. public static void main(String[] args) {
  17. Connection connection = null;
  18. Channel channel = null;
  19. try {
  20. ConnectionFactory connectionFactory = new ConnectionFactory();
  21. connectionFactory.setHost("127.0.0.1");//mq服务ip地址
  22. connectionFactory.setPort(5672);//mq client连接端口
  23. connectionFactory.setUsername("guest");//mq登录用户名
  24. connectionFactory.setPassword("guest");//mq登录密码
  25. connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
  26. //创建与RabbitMQ服务的TCP连接
  27. connection = connectionFactory.newConnection();
  28. //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
  29. channel = connection.createChannel();
  30. //通道绑定交换机
  31. /**
  32.              * 参数明细
  33.              * 1、交换机名称
  34.              * 2、交换机类型,fanout、topic、direct、headers
  35.              */
  36. //Header 模式
  37. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
  38. //通道绑定队列
  39. /**
  40. * 声明队列,如果Rabbit中没有此队列将自动创建
  41. * param1:队列名称
  42. * param2:是否持久化
  43. * param3:队列是否独占此连接
  44. * param4:队列不再使用时是否自动删除此队列
  45. * param5:队列参数
  46. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  47. *
  48. */
  49. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  50. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
  51. //交换机和队列绑定
  52. /**
  53. * 参数明细
  54. * 1、队列名称
  55. * 2、交换机名称
  56. * 3、路由key
  57. * 4、
  58. * String queue, String exchange, String routingKey, Map<String, Object> arguments
  59. */
  60. Map<String,Object> headers_email = new Hashtable<String,Object>();
  61. headers_email.put("inform_type","email");
  62. Map<String,Object> headers_sms = new Hashtable<String, Object>();
  63. headers_sms.put("inform_type","sms");
  64. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);
  65. channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_sms);
  66. //给email队列发消息
  67. for(int i = 0;i<10;i++){
  68. String message = new String("mq 发送email消息。。。");
  69. Map<String,Object> headers = new Hashtable<String,Object>();
  70. headers.put("inform_type","email");//匹配email通知消费者绑定的header
  71. /**
  72.              * 消息发布方法
  73.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  74.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  75.              * param3:消息包含的属性
  76.              * param4:消息体
  77.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  78.  * 默认的交换机,routingKey等于队列名称
  79. */
  80. //String exchange, String routingKey, BasicProperties props, byte[] body
  81. AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
  82. properties.headers(headers);
  83. //Email通知
  84. channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());
  85. System.out.println("mq email 消息发送成功!");
  86. }
  87. //给sms队列发消息
  88. for(int i = 0;i<10;i++){
  89. String message = new String("mq 发送sms消息。。。");
  90. Map<String,Object> headers = new Hashtable<String,Object>();
  91. headers.put("inform_type","sms");//匹配sms通知消费者绑定的header
  92. /**
  93.              * 消息发布方法
  94.              * param1:Exchange的名称,如果没有指定,则使用Default Exchange
  95.              * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
  96.              * param3:消息包含的属性
  97.              * param4:消息体
  98.  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
  99.  * 默认的交换机,routingKey等于队列名称
  100. */
  101. //String exchange, String routingKey, BasicProperties props, byte[] body
  102. AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
  103. properties.headers(headers);
  104. //sms通知
  105. channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());
  106. System.out.println("mq sms 消息发送成功!");
  107. }
  108. } catch (Exception e) {
  109. e.printStackTrace();
  110. } finally {
  111. try {
  112. channel.close();
  113. } catch (IOException e) {
  114. e.printStackTrace();
  115. } catch (TimeoutException e) {
  116. e.printStackTrace();
  117. }
  118. try {
  119. connection.close();
  120. } catch (IOException e) {
  121. e.printStackTrace();
  122. }
  123. }
  124. }
  125. }

邮件消费端的代码如下:

  1. package com.xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.Hashtable;
  7. import java.util.Map;
  8. import java.util.concurrent.TimeoutException;
  9.  
  10. public class Consumer05 {
  11. private static final String QUEUE_EMAIL ="queueEmail";
  12. private static final String EXCHANGE = "messageChange";
  13. public static void main(String[] args) {
  14. Connection connection = null;
  15. Channel channel = null;
  16. try {
  17. ConnectionFactory connectionFactory = new ConnectionFactory();
  18. connectionFactory.setHost("127.0.0.1");
  19. connectionFactory.setPort(5672);
  20. connection = connectionFactory.newConnection();
  21. channel = connection.createChannel();
  22. //通道绑定交换机
  23. /**
  24.              * 参数明细
  25.              * 1、交换机名称
  26.              * 2、交换机类型,fanout、topic、direct、headers
  27.              */
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. * 4、
  48. * String queue, String exchange, String routingKey, Map<String, Object> arguments
  49. */
  50. Map<String,Object> headers_email = new Hashtable<String,Object>();
  51. headers_email.put("inform_email","email");
  52. channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);
  53. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  54. DefaultConsumer consumer = new DefaultConsumer(channel) {
  55. /**
  56.              * 消费者接收消息调用此方法
  57.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  58.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  59. (收到消息失败后是否需要重新发送)
  60.              * @param properties
  61.              * @param body
  62.              * @throws IOException
  63. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  64. */
  65. @Override
  66. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  67. //交换机
  68. String exchange = envelope.getExchange();
  69. //路由key
  70. String routingKey = envelope.getRoutingKey();
  71. envelope.getDeliveryTag();
  72. String msg = new String(body,"utf-8");
  73. System.out.println("mq收到的消息是:"+msg );
  74. }
  75.  
  76. };
  77. System.out.println("消费者启动成功!");
  78. channel.basicConsume(QUEUE_EMAIL,true,consumer);
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. } catch (TimeoutException e) {
  82. e.printStackTrace();
  83. }
  84. }
  85. }

短信消费端的代码如下:

  1. package xyfer;
  2.  
  3. import com.rabbitmq.client.*;
  4.  
  5. import java.io.IOException;
  6. import java.util.Hashtable;
  7. import java.util.Map;
  8. import java.util.concurrent.TimeoutException;
  9.  
  10. public class Consumer05 {
  11. private static final String QUEUE_SMS ="queueSms";
  12. private static final String EXCHANGE = "messageChange";
  13. public static void main(String[] args) {
  14. Connection connection = null;
  15. Channel channel = null;
  16. try {
  17. ConnectionFactory connectionFactory = new ConnectionFactory();
  18. connectionFactory.setHost("127.0.0.1");
  19. connectionFactory.setPort(5672);
  20. connection = connectionFactory.newConnection();
  21. channel = connection.createChannel();
  22. //通道绑定交换机
  23. /**
  24.              * 参数明细
  25.              * 1、交换机名称
  26.              * 2、交换机类型,fanout、topic、direct、headers
  27.              */
  28. channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
  29. //通道绑定队列
  30. /**
  31. * 声明队列,如果Rabbit中没有此队列将自动创建
  32. * param1:队列名称
  33. * param2:是否持久化
  34. * param3:队列是否独占此连接
  35. * param4:队列不再使用时是否自动删除此队列
  36. * param5:队列参数
  37. * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
  38. *
  39. */
  40. channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列
  41. //交换机和队列绑定
  42. /**
  43. * 参数明细
  44. * 1、队列名称
  45. * 2、交换机名称
  46. * 3、路由key
  47. * 4、
  48. * String queue, String exchange, String routingKey, Map<String, Object> arguments
  49. */
  50. Map<String,Object> headers_email = new Hashtable<String,Object>();
  51. headers_email.put("inform_email","sms");
  52. channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_email);
  53. //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  54. DefaultConsumer consumer = new DefaultConsumer(channel) {
  55. /**
  56.              * 消费者接收消息调用此方法
  57.              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
  58.              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
  59. (收到消息失败后是否需要重新发送)
  60.              * @param properties
  61.              * @param body
  62.              * @throws IOException
  63. * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
  64. */
  65. @Override
  66. public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
  67. //交换机
  68. String exchange = envelope.getExchange();
  69. //路由key
  70. String routingKey = envelope.getRoutingKey();
  71. envelope.getDeliveryTag();
  72. String msg = new String(body,"utf-8");
  73. System.out.println("mq收到的消息是:"+msg );
  74. }
  75.  
  76. };
  77. System.out.println("消费者启动成功!");
  78. channel.basicConsume(QUEUE_SMS,true,consumer);
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. } catch (TimeoutException e) {
  82. e.printStackTrace();
  83. }
  84. }
  85. }

生产端启动后RabbitMQ上面的消息队列情况:

六、RPC 模式

RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:

1、客户端即是生产者也是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。

2、服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果。

3、服务端将RPC方法 的结果发送到RPC响应队列。

4、客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。

至此,RabbitMQ的六种工作模式已经介绍完毕,手动代码实现,实际体验六种工作模式的不同。

RabbitMQ的六种工作模式总结的更多相关文章

  1. RabbitMQ的六种工作模式

    一.基于erlang语言: 是一种支持高并发的语言 RabbitMQ的六种工作模式: 1.1 simple简单模式 消息产生着§将消息放入队列 消息的消费者(consumer) 监听(while) 消 ...

  2. SpringBoot整合RabbitMQ实现六种工作模式

    RabbitMQ主要有六种种工作模式,本文整合SpringBoot分别介绍工作模式的实现. 前提概念 生产者 消息生产者或者发送者,使用P表示: 队列 消息从生产端发送到消费端,一定要通过队列转发,使 ...

  3. rabbitmq官方的六种工作模式

    1.RabbitMq1.1介绍RabbitMQ是一个消息代理:它接受并转发消息.你可以把它当成一个邮局:当你想邮寄信件的时候,你会把信件放在投递箱中,并确信邮递员最终会将信件送到收件人的手里.在这个例 ...

  4. 面试官:RabbitMQ有哪些工作模式?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 今天又.又.又来面试了,还是老规 ...

  5. RabbitMQ六种工作模式有哪些?怎样用SpringBoot整合RabbitMQ

    目录 一.RabbitMQ入门程序 二.Work queues 工作模式 三.Publish / Subscribe 发布/订阅模式 四.Routing 路由模式 五.Topics 六.Header ...

  6. RabbitMQ从零到集群高可用(.NetCore5.0) - RabbitMQ简介和六种工作模式详解

    一.RabbitMQ简介 是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang(高并发语言)语言来编写的,并且RabbitMQ是基于AMQ ...

  7. RabbitMQ 五种工作模式

    官网介绍:https://www.rabbitmq.com/getstarted.html 五种工作模式的主要特点 简单模式:一个生产者,一个消费者 work模式:一个生产者,多个消费者,每个消费者获 ...

  8. RabbitMQ之六种队列模式

    先学习一下RabbitMQ中的六种队列,只学习前五种,具体的官方文档地址是:http://next.rabbitmq.com/getstarted.html 导入maven依赖: <depend ...

  9. RabbitMQ工作模式

    ------------恢复内容开始------------ RabbitMQ基本概念: Producer:生产者(消息的提供者) Consumer:消费者(消息的使用者) Message:消息(程序 ...

随机推荐

  1. RSA加密的java实现2(交互IOS)

    这里的base64的依赖不一样,一个是apache,一个是sun的  ,由于base64的依赖不同,导致在IOS中解析不了! package com.handsight.platform.cipher ...

  2. Redis学习总结(三)--Redis持久化

    Redis 是将数据存储在内存中的,如果出现断电或系统故障的时候数据就会存在丢失的现象,Redis通过将数据持久化到硬盘中来避免这个问题的出现,我们今天就来学习下 Redis 持久化. Redis 持 ...

  3. 支持向量机 (一): 线性可分类 svm

    支持向量机(support vector machine, 以下简称 svm)是机器学习里的重要方法,特别适用于中小型样本.非线性.高维的分类和回归问题.本系列力图展现 svm 的核心思想和完整推导过 ...

  4. ZOJ - 3870-Team Formation二进制,位运算

    传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3870 题意:找出一个数列中的两个数,所有通过异或和使得结果同时大于 ...

  5. 主席树区间第K大

    主席树的实质其实还是一颗线段树, 然后每一次修改都通过上一次的线段树,来添加新边,使得每次改变就改变logn个节点,很多节点重复利用,达到节省空间的目的. 1.不带修改的区间第K大. HDU-2665 ...

  6. 牛客多校第五场 E room 二分图匹配 KM算法模板

    链接:https://www.nowcoder.com/acm/contest/143/E来源:牛客网 Nowcoder University has 4n students and n dormit ...

  7. CH4301 Can you answer on these queries III 题解

    给定长度为N的数列A,以及M条指令 (N≤500000, M≤100000),每条指令可能是以下两种之一: "2 x y",把 A[x] 改成 y. "1 x y&quo ...

  8. yzoj1657货仓选址 题解

    题面: 在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N].现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品.为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的 ...

  9. 基于 APIGateway 打造生产级别的 Knative 服务

    作者 | 阿里云智能事业群高级开发工程师  元毅 导读:在实际应用中,通过 APIGateway(即 API 网关),可以为内部服务提供保护.提供统一的鉴权管理.限流.监控等能力,开发人员只需要关注内 ...

  10. PHP 通过curl POST传递 伪造cookie 传递信息

    一些论坛网站需要每日签到太麻烦,于是写了一个Win 的定时任务,通过curl 去处理传递的伪造Cookie 和 header; 有不妥的地方,希望各位大佬们多多指正,谢谢各位大佬: $fp = @fo ...