最近学习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文件中依赖坐标如下:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.0</version>
</dependency>
</dependencies>

生产端的代码如下:

package com.xyfer;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import java.io.IOException;
import java.util.concurrent.TimeoutException;
/*
1、声明队列
2、创建连接
3、创建通道
4、通道声明队列
5、制定消息
6、发送消息,使用默认交换机
*/
public class Producer02 {
//声明队列
private static final String QUEUE ="queue";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");//mq服务ip地址
connectionFactory.setPort(5672);//mq client连接端口
connectionFactory.setUsername("guest");//mq登录用户名
connectionFactory.setPassword("guest");//mq登录密码
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
//创建与RabbitMQ服务的TCP连接
connection = connectionFactory.newConnection();
//创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
channel = connection.createChannel(); //通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列 for(int i = 0;i<10;i++){
String message = new String("mq 发送消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish("",QUEUE,null,message.getBytes("utf-8"));
System.out.println("mq消息发送成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

消费端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;
/*
1、声明队列
2、创建连接
3、创建通道
4、通道声明队列
5、重写消息消费方法
6、执行消息方法
*/
public class Consumer02 {
private static final String QUEUE ="queue";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列 //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE,true,consumer); } catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

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

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 模式绑定两个消费端,因此需要有两个消费端,一个邮件消费端,一个短信消费端;

生产端的代码如下:

package com.xyfer;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Producer01 {
//声明两个队列和一个交换机
//Publish/subscribe发布订阅模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");//mq服务ip地址
connectionFactory.setPort(5672);//mq client连接端口
connectionFactory.setUsername("guest");//mq登录用户名
connectionFactory.setPassword("guest");//mq登录密码
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
//创建与RabbitMQ服务的TCP连接
connection = connectionFactory.newConnection();
//创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Publish/subscribe发布订阅模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Publish/subscribe发布订阅模式
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");
channel.queueBind(QUEUE_SMS,EXCHANGE,"");
for(int i = 0;i<10;i++){
String message = new String("mq 发送消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
//Publish/subscribe发布订阅模式
channel.basicPublish(EXCHANGE,"",null,message.getBytes());
System.out.println("mq消息发送成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

邮件消费端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer01 {
//Publish/subscribe发布订阅模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Publish/subscribe发布订阅模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Publish/subscribe发布订阅模式
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
}
};
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_EMAIL,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

短信消费端的代码如下:

package xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer01 {
//Publish/subscribe发布订阅模式
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Publish/subscribe发布订阅模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Publish/subscribe发布订阅模式
channel.queueBind(QUEUE_SMS,EXCHANGE,"");
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_SMS,true,consumer); } catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

三、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就能把相应的消息发送到相应的队列中去。

生产端的代码如下:

package com.xyfer;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Producer03 {
//声明两个队列和一个交换机
//Routing 路由模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");//mq服务ip地址
connectionFactory.setPort(5672);//mq client连接端口
connectionFactory.setUsername("guest");//mq登录用户名
connectionFactory.setPassword("guest");//mq登录密码
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
//创建与RabbitMQ服务的TCP连接
connection = connectionFactory.newConnection();
//创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Routing 路由模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Routing 路由模式
channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);
channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);
//给email队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送email消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
//Routing 路由模式
channel.basicPublish(EXCHANGE,QUEUE_EMAIL,null,message.getBytes());
System.out.println("mq消息发送成功!");
}
//给sms队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送sms消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
//Routing 路由模式
channel.basicPublish(EXCHANGE,QUEUE_SMS,null,message.getBytes());
System.out.println("mq消息发送成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

邮件消费端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer03 {
//Routing 路由模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Routing 路由模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Routing 路由模式
channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_EMAIL,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

短信消费端的代码如下:

package xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer03 {
//Routing 路由模式
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Routing 路由模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
//Routing 路由模式
channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
}
};
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_SMS,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

四、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也是通配符,这样就能根据通配符匹配到消息了。

生产端的代码如下:

package com.xyfer;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Producer04 {
//声明两个队列和一个交换机
//Topics 模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");//mq服务ip地址
connectionFactory.setPort(5672);//mq client连接端口
connectionFactory.setUsername("guest");//mq登录用户名
connectionFactory.setPassword("guest");//mq登录密码
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
//创建与RabbitMQ服务的TCP连接
connection = connectionFactory.newConnection();
//创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Topics 模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");
channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");
//给email队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送email消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE,"inform.email",null,message.getBytes());
System.out.println("mq email 消息发送成功!");
}
//给sms队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送sms消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE,"inform.sms",null,message.getBytes());
System.out.println("mq sms 消息发送成功!");
}
//给email和sms队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送email sms消息。。。");
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE,"inform.email.sms",null,message.getBytes());
System.out.println("mq email sms 消息发送成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

邮件消费端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer04 {
private static final String QUEUE_EMAIL ="queueEmail";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_EMAIL,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

短信消费端的代码如下:

package xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class Consumer04 {
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
*/
channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_SMS,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

由于生产端同时发送了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(键值对)匹配队列。

生产端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeoutException; public class Producer05 {
//声明两个队列和一个交换机
//Header 模式
private static final String QUEUE_EMAIL ="queueEmail";
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");//mq服务ip地址
connectionFactory.setPort(5672);//mq client连接端口
connectionFactory.setUsername("guest");//mq登录用户名
connectionFactory.setPassword("guest");//mq登录密码
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
//创建与RabbitMQ服务的TCP连接
connection = connectionFactory.newConnection();
//创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
//Header 模式
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
* 4、
* String queue, String exchange, String routingKey, Map<String, Object> arguments
*/
Map<String,Object> headers_email = new Hashtable<String,Object>();
headers_email.put("inform_type","email");
Map<String,Object> headers_sms = new Hashtable<String, Object>();
headers_sms.put("inform_type","sms");
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);
channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_sms);
//给email队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送email消息。。。");
Map<String,Object> headers = new Hashtable<String,Object>();
headers.put("inform_type","email");//匹配email通知消费者绑定的header
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
properties.headers(headers);
//Email通知
channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());
System.out.println("mq email 消息发送成功!");
}
//给sms队列发消息
for(int i = 0;i<10;i++){
String message = new String("mq 发送sms消息。。。");
Map<String,Object> headers = new Hashtable<String,Object>();
headers.put("inform_type","sms");//匹配sms通知消费者绑定的header
/**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息包含的属性
             * param4:消息体
 * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
 * 默认的交换机,routingKey等于队列名称
*/
//String exchange, String routingKey, BasicProperties props, byte[] body
AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
properties.headers(headers);
//sms通知
channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());
System.out.println("mq sms 消息发送成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

邮件消费端的代码如下:

package com.xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeoutException; public class Consumer05 {
private static final String QUEUE_EMAIL ="queueEmail";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
* 4、
* String queue, String exchange, String routingKey, Map<String, Object> arguments
*/
Map<String,Object> headers_email = new Hashtable<String,Object>();
headers_email.put("inform_email","email");
channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_EMAIL,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

短信消费端的代码如下:

package xyfer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeoutException; public class Consumer05 {
private static final String QUEUE_SMS ="queueSms";
private static final String EXCHANGE = "messageChange";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//通道绑定交换机
/**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);
//通道绑定队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
*
*/
channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列
//交换机和队列绑定
/**
* 参数明细
* 1、队列名称
* 2、交换机名称
* 3、路由key
* 4、
* String queue, String exchange, String routingKey, Map<String, Object> arguments
*/
Map<String,Object> headers_email = new Hashtable<String,Object>();
headers_email.put("inform_email","sms");
channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_email);
//String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
(收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
* String consumerTag, Envelope envelope, BasicProperties properties, byte[] body
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
envelope.getDeliveryTag();
String msg = new String(body,"utf-8");
System.out.println("mq收到的消息是:"+msg );
} };
System.out.println("消费者启动成功!");
channel.basicConsume(QUEUE_SMS,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

生产端启动后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. Scrum 工件: 速度图和燃尽图

    速度图 Velocity用于衡量scrum团队持续提供业务价值的速度,可以采用历史估算的方法,衡量一个又一个sprint的速度.团队通过跟踪完成达到自己团队完成标准的故事点的数量,就可以基于相对点值对 ...

  2. 单元测试之NUnit一

    NUnit 分三篇文章介绍,入门者可阅读文章,有基础者直接参考官方文档.初次写博客,望大家指点. 导航: 单元测试之NUnit一 单元测试之NUnit二 单元测试之NUnit三 NUnit是什么? N ...

  3. python 21 面向对象

    目录 1. 面向对象初步认识 2. 面向对象的结构 3. 从类名的角度研究类 3.1 类名操作类中的属性 3.2 类名调用类中的方法 4. 从对象的角度研究类 4.1 类名() 4.2 对象操作对象空 ...

  4. 设计模式(C#)——02简单工厂模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321       工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来.通俗来说,你只关心怎么用,不用关心怎么做 ...

  5. Java IO体系之RandomAccessFile浅析

    Java IO体系之RandomAccessFile浅析 一.RandomAccessFile综述: 1.1RandomAccessFile简介 RandomAccessFile是java Io体系中 ...

  6. JavaScript 运行机制以及Event Loop(事件循环)

    一.JavaScript单线程 众所周知JavaScript是一门单线程语言,也就是说,在同一时间内JS只能做一件事.为什么JavaScript不能有多个线程呢?这样不是能够提高效率吗? JavaSc ...

  7. Python连载35-死锁问题以及解决方式

    一.死锁问题 例子 import threading import time ​ lock_1 = threading.Lock() lock_2 = threading.Lock() ​ def f ...

  8. 【Appium】Appium+Python环境搭建

    环境准备: 1.jdk 2.android-sdk 3.python 4.Node.js 5.appium 6.Appium-Python-Client 1. 下载jdk1.7:http://www. ...

  9. Codeforces 369 C Valera and Elections

    Valera and Elections 题意:现在有n个候选人, 有n-1条路, 如果选择了这个候选人, 这个候选人就会将从自己这个城市到1号城市上所有坏的路都修复一下,现在求最小的候选人数目, 如 ...

  10. CodeForces 982 C Cut 'em all!

    Cut 'em all! 题意:求删除了边之后,剩下的每一块联通块他的点数都为偶数,求删除的边最多能是多少. 题解:如果n为奇数,直接返回-1,因为不可能成立.如果n为偶数,随意找一个点DFS建树记录 ...