系列文章
RabbitMq系列(七):直接交换Direct exchange
RabbitMq系列(八):扇出交换Fanout Exchange
RabbitMq系列(九):主题交换Topic Exchange
RabbitMq系列(十):标头交换Headers exchange
目录
前言
RabbitMq系列(二):最简单的例子编写了一个最简单的例子来进行消息通信的测试,其只有一个生产者和一个消费者。这里我们使用工作队列(Work Queue)来进行一个生产者多个消费者的测试。
工作队列(Work Queue)主要思想是避免执行密集性任务,将任务放在以后执行。在我们将消息放在队列中时,我们可以启用多个消费者进行消费,他们之间共享消息(一个消息仅被消费一次)
工作队列
工作队列不但能轻松并行化工作,还能够根据需求扩展,能满足大部分业务的处理速度和应用场景,在spring里面,还封装有相关的配置,例如:空闲消费者数和最大消费者数等等,下面运行两个消费者,代码都一样。
- 消费者1
/**
* 消费者1
*
* @Tag 工厂队列
*/
public class MQConsumerOne {
public static void main(String[] args) {
try {
consumerMsg("work.queue");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 消费消息
* @param queue
*/
public static void consumerMsg(String queue) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置代理地址
connectionFactory.setHost("192.168.239.128");
//设置连接端口(默认配置)
connectionFactory.setPort(5672);
//设置连接用户(默认配置)
connectionFactory.setUsername("guest");
//设置连接密码(默认配置)
connectionFactory.setPassword("guest");
//设置连接虚拟机(默认配置)
connectionFactory.setVirtualHost("/");
//创建连接
Connection connection = connectionFactory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare("work.exchange", BuiltinExchangeType.DIRECT,false,true,null);
//声明队列
channel.queueDeclare(queue,false,false,true,null);
//绑定队列
channel.queueBind(queue,"work.exchange","");
//创建消费者
channel.basicConsume(queue,true,(consumerTag,message)->{
//打印消息
try {
Thread.sleep(Math.round(Math.random()*2000)+1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new String(message.getBody(),"UTF-8"));
},(consumerTag) -> {
//打印用户标记
System.out.println(consumerTag);
});
//关闭连接
/* channel.close();
connection.close();*/
}
}
- 消费者2
**
* 消费者2
*
* @Tag 工厂队列
*/
public class MQConsumerTwo {
public static void main(String[] args) {
try {
consumerMsg("work.queue");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 消费消息
* @param queue
*/
public static void consumerMsg(String queue) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置代理地址
connectionFactory.setHost("192.168.239.128");
//设置连接端口(默认配置)
connectionFactory.setPort(5672);
//设置连接用户(默认配置)
connectionFactory.setUsername("guest");
//设置连接密码(默认配置)
connectionFactory.setPassword("guest");
//设置连接虚拟机(默认配置)
connectionFactory.setVirtualHost("/");
//创建连接
Connection connection = connectionFactory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare("work.exchange", BuiltinExchangeType.DIRECT,false,true,null);
//声明队列
channel.queueDeclare(queue,false,false,true,null);
//绑定队列
channel.queueBind(queue,"work.exchange","");
//创建消费者
channel.basicConsume(queue,true,(consumerTag,message)->{
//打印消息
try {
Thread.sleep(Math.round(Math.random()*20000)+1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new String(message.getBody(),"UTF-8"));
},(consumerTag) -> {
//打印用户标记
System.out.println(consumerTag);
});
//关闭连接
/* channel.close();
connection.close();
*/
}
}
-
运行两个消费者,查看管理UI (这里http://192.168.239.128:15672)的参数变化,这里只看主要的,我们声明的
1) exchange (交换机,类似家里面的路由器)
2) queue (队列,消息缓存所在,下面是点进去的展示)
- 生产者(部分配置有默认值,可以不写)
/**
* 生产者
*
* @Tag 工厂队列
*/
public class MQProducer {
public static void main(String[] args) {
for (int count=0;count<10;count++)
{
try {
produceMsg("work.queue","来啦,老弟!我是你老姐"+count);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void produceMsg(String queue,String msg) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置代理地址
connectionFactory.setHost("192.168.239.128");
//创建连接
Connection connection = connectionFactory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare("work.exchange", BuiltinExchangeType.DIRECT,false,true,null);
//创建生产者
channel.basicPublish("work.exchange","",null, msg.getBytes());
//关闭连接
channel.close();
connection.close();
}
}
生产者不关心自己的消息被谁使用,怎么样使用,所以不会绑定队列
- 为了方便测试写一个简单的循环发送消息
for (int count=0;count<10;count++)
{
try {
produceMsg("work.queue","来啦,老弟!我是你老姐"+count);
} catch (Exception e) {
e.printStackTrace();
}
}
- 运行生产者,查看结果
可以很明显的看出来,消息是在两个消费者之间轮询消费的,简称循环调用(Round-robin dispatching),轮询模式是工作队列默认的模式,除此之外还有单一消费者模式,这个需要在声明队列的时候传参。