RabbitMQ队列类型
RabbitMQ分为一下几种队列
Work queues(工作队列)

工作队列的主要思想就是将资源密集型的任务分配给多个终端处理,可以理解为轮询机制
。
实现思路:
1、创建两个消费者
2、创建一个生产者
3、生产者向队列中发送多个条消息,消费者们会遵循逐个接收的概念,去处理从生产者提供的消息。

Publish/Subscribe(发布/订阅)

发布/订阅队列概念是将生产者发布的消息以广播的形式发送给所有消费者,例如我们在QQ群里发送了一条消息,所有人的都可以接收到。
创建生产者
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author: Yizq
* @data: 2020/10/11 21:30
*/
public class Producer02_publish {
//队列名称
private static final String QUEUE_INFORM_DOCTOR1 = "doctor1";
private static final String QUEUE_INFORM_DOCTOR2 = "doctor2";
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
/*
一、与RabbitMQ建立连接
*/
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置主机IP(如果是本地使用localhost)
connectionFactory.setHost("192.168.174.131");
// rabbitMq默认的端口号
connectionFactory.setPort(5672);
// 访问的用户名
connectionFactory.setUsername("guest");
// 访问的密码
connectionFactory.setPassword("guest");
// RabbitMQ默认的虚拟机名称为"/",虚拟机相当于一个独立的mq服务
connectionFactory.setVirtualHost("/");
/*
二、创建通道
*/
connection = connectionFactory.newConnection();
channel = connection.createChannel();
/*
三、创建交换机
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
/*
三、声明队列
*/
channel.queueDeclare(QUEUE_INFORM_DOCTOR1, true, false, false, null);
channel.queueDeclare(QUEUE_INFORM_DOCTOR2, true, false, false, null);
/*
四、交换机和队列绑定
*/
channel.queueBind(QUEUE_INFORM_DOCTOR1, EXCHANGE_FANOUT_INFORM, "");
channel.queueBind(QUEUE_INFORM_DOCTOR2, EXCHANGE_FANOUT_INFORM, "");
/*
五、消息发布
*/
for (int i = 0; i < 5; i++) {
String message = "seeADoctor" + i;
channel.basicPublish(EXCHANGE_FANOUT_INFORM, "", null, message.getBytes());
System.out.println("Send Message is:" + message);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
创建交换机涉及的两个参数:
- String exchange:交换机的名称
- BuiltinExchangeType type:交换机的类型
- BuiltinExchangeType.FANOUT:对应的是Publish/Subscribe队列
- BuiltinExchangeType.DIRECT:对应的是routing队列
- BuiltinExchangeType.topic:对应的是topic队列
- BuiltinExchangeType.headers:对应的是RFC队列
创建消费者1号
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author: Yizq
* @data: 2020/10/11 21:40
*/
public class Consumer02_subscribe_doctor1 {
//队列名称
//队列名称
private static final String QUEUE_INFORM_DOCTOR1 = "doctor1";
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
/*
一、建立连接
*/
// 设置主机IP(如果是本地使用localhost)
connectionFactory.setHost("192.168.174.131");
// rabbitMq默认的端口号
connectionFactory.setPort(5672);
// 访问的用户名
/*
二、创建通道
*/
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
/*
三、声明交换机
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
/*
四、声明队列
*/
channel.queueDeclare(QUEUE_INFORM_DOCTOR1, true, false, false, null);
/*
五、队列和交换机绑定
*/
channel.queueBind(QUEUE_INFORM_DOCTOR1, EXCHANGE_FANOUT_INFORM, "");
/*
六、监听队列
*/
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 交换机
String exchange = envelope.getExchange();
// 路由key
String routingKey = envelope.getRoutingKey();
// 消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
// 消息内容
String mes = new String(body, StandardCharsets.UTF_8);
System.out.println("receive message.. " + mes);
}
};
channel.basicConsume(QUEUE_INFORM_DOCTOR1, true, defaultConsumer);
}
}
创建消费者二号(省略)
Routing(路由)

路由队列概念是将特定的事情交给专业的人去处理,例如去医院看病,每一个医生都有自己的特长(routingKey),感冒发烧要去找医生A,胃病要去找医生B。
创建生产者
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author: Yizq
* @data: 2020/10/11 21:30
*/
public class Producer03_routing {
//队列名称
private static final String QUEUE_INFORM_DOCTOR1 = "doctor1";
private static final String QUEUE_INFORM_DOCTOR2 = "doctor2";
private static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
/*
一、与RabbitMQ建立连接
*/
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置主机IP(如果是本地使用localhost)
connectionFactory.setHost("192.168.174.131");
// rabbitMq默认的端口号
connectionFactory.setPort(5672);
// 访问的用户名
connectionFactory.setUsername("guest");
// 访问的密码
connectionFactory.setPassword("guest");
// RabbitMQ默认的虚拟机名称为"/",虚拟机相当于一个独立的mq服务
connectionFactory.setVirtualHost("/");
/*
二、创建通道
*/
connection = connectionFactory.newConnection();
channel = connection.createChannel();
/*
三、创建交换机
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
/*
三、声明队列
*/
channel.queueDeclare(QUEUE_INFORM_DOCTOR1, true, false, false, null);
channel.queueDeclare(QUEUE_INFORM_DOCTOR2, true, false, false, null);
/*
四、交换机和队列绑定
*/
channel.queueBind(QUEUE_INFORM_DOCTOR1, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR1);
channel.queueBind(QUEUE_INFORM_DOCTOR2, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR2);
/*
五、消息发布
*/
String message1 = "感冒找医生1";
channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR1, null, message1.getBytes());
System.out.println("Send Message is:" + message1);
String message2 = "胃病找医生2";
channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR2, null, message2.getBytes());
System.out.println("Send Message is:" + message2);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
注意:这里用到的交换机类型是
BuiltinExchangeType.DIRECT
创建消费者1号(医生1)
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author: Yizq
* @data: 2020/10/11 21:40
*/
public class Consumer02_routing_doctor1 {
//队列名称
private static final String QUEUE_INFORM_DOCTOR1 = "doctor1";
private static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
/*
一、建立连接
*/
// 设置主机IP(如果是本地使用localhost)
connectionFactory.setHost("192.168.174.131");
// rabbitMq默认的端口号
connectionFactory.setPort(5672);
/*
二、创建通道
*/
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
/*
三、声明交换机
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
/*
四、声明队列
*/
channel.queueDeclare(QUEUE_INFORM_DOCTOR1, true, false, false, null);
/*
五、队列和交换机绑定
*/
channel.queueBind(QUEUE_INFORM_DOCTOR1, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR1);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 交换机
String exchange = envelope.getExchange();
// 路由key
String routingKey = envelope.getRoutingKey();
// 消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
// 消息内容
String mes = new String(body, StandardCharsets.UTF_8);
System.out.println("receive message.. " + mes);
}
};
/*
六、监听队列
*/
channel.basicConsume(QUEUE_INFORM_DOCTOR1, true, defaultConsumer);
}
}
创建消费者2号(医生2)
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author: Yizq
* @data: 2020/10/11 21:40
*/
public class Consumer02_routing_doctor2 {
//队列名称
private static final String QUEUE_INFORM_DOCTOR2 = "doctor2";
private static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
/*
一、建立连接
*/
// 设置主机IP(如果是本地使用localhost)
connectionFactory.setHost("192.168.174.131");
// rabbitMq默认的端口号
connectionFactory.setPort(5672);
/*
二、创建通道
*/
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
/*
三、声明交换机
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
/*
四、声明队列
*/
channel.queueDeclare(QUEUE_INFORM_DOCTOR2, true, false, false, null);
/*
五、队列和交换机绑定
*/
channel.queueBind(QUEUE_INFORM_DOCTOR2, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_DOCTOR2);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 交换机
String exchange = envelope.getExchange();
// 路由key
String routingKey = envelope.getRoutingKey();
// 消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
// 消息内容
String mes = new String(body, StandardCharsets.UTF_8);
System.out.println("receive message.. " + mes);
}
};
/*
六、监听队列
*/
channel.basicConsume(QUEUE_INFORM_DOCTOR2, true, defaultConsumer);
}
}
每个交换定和队列绑定的时候,需要指定消费者的标识(routingKey)
Topics(通配符)

通配符队列顾名思义就是通过routingkey的基础上添加了模糊匹配的操作,实现思路和routing大同小异,需要注意的是
channel.exchangeDeclare(EXCHANGE_TOPICS_INFORM, BuiltinExchangeType.TOPIC);
// 将创建的交换机更换类型
PRC

RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:
1、客户端即是生产者就是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。
2、服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果
3、服务端将RPC方法 的结果发送到RPC响应队列
4、客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果