参考官方文档
rabbitmq
版本:3.8.3
amqp-client
版本:5.7.1
工作队列模式:一个生产者,一个消息队列,多个消费者,同样也称为点对点模式。
工作队列模式的最大特点就是有多个消费者,这样就不会因为处理耗时的任务导致MQ
不可用。
默认情况下,rabbitmq
将会按顺序派发每个任务给下一个消费者,平均而言,每个消费者将获得相同数量的消息,这种分发消息的方式称为轮询。
amqp-client
依赖<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.7.1version>
dependency>
/**
* 生成者
*/
public class Producer {
public static final String WORK_QUEUE = "work-queue";
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.99.100");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("password");
// 2、获取连接、通道
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// 3、声明发送消息的队列
channel.queueDeclare(WORK_QUEUE, true, false, false, null);
// 4、限制一次只分发一个消息给同一个消费者
channel.basicQos(1);
// 5、发送消息
int count = 1;
while (true) {
String message = "Simple Queue Message, count = " + count;
count++;
channel.basicPublish("", WORK_QUEUE, null, message.getBytes());
System.out.println("Send message: " + message);
Thread.sleep(2000);
}
} catch (TimeoutException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
几点说明:
channel.queueDeclare(WORK_QUEUE, true, false, false, null);
第二个参数置为true
,表示设置队列为持久化队列,当rabbitmq
崩溃之后,队列将被保存,当rabbitmq
恢复之后,队列将会恢复,但是不是100%
一定持久化。channel.basicQos(1);
设置一次只分发一个消息给同一个消费者,这样保证有多个消费者的时候不会其中一个一直在消费消息,而其他的消费者处于空闲状态。/**
* 多个消费者
*/
public class Consumers {
// 启动两个消费者
public static void main(String[] args) {
// 消费者1
new Thread(() -> {
try {
new Consumer(1).start();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}).start();
// 消费者2
new Thread(() -> {
try {
new Consumer(2).start();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}).start();
}
}
/**
* 消费者
*/
class Consumer {
public static final String WORK_QUEUE = "work-queue";
private int no = 0;
public Consumer(int no) {
this.no = no;
}
/**
* 启动
* @throws IOException
* @throws TimeoutException
*/
public void start() throws IOException, TimeoutException {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.99.100");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("password");
// 2、获取连接、通道
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 3、声明监听的队列
channel.queueDeclare(WORK_QUEUE, true, false, false, null);
System.out.println(String.format("Consumer %d Waiting for messages. To exit press CTRL+C", this.no));
// 4、监听并消费消息
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(String.format("Consumer %d received message: %s", this.no, message));
try {
// 执行任务
doWork(message);
} finally {
System.out.println(String.format("Consumer %d work done", this.no));
// 手动ACK
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
// 监听消息,关闭自动ACK
channel.basicConsume(WORK_QUEUE, false, deliverCallback, consumerTag -> { });
}
/**
* 执行任务
* @param message
*/
private void doWork(String message) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
几点说明:
channel.basicConsume(WORK_QUEUE, false, deliverCallback, consumerTag -> { });
第二个参数设置为false
,关闭自动ACK
。DeliverCallback
中,使用try...finally
将代码包裹起来并在finally
中手动进行ACK
。首先,启动2
个消费者,消费者处于异步监听消息的状态。
然后,启动发送者,每隔2
秒发送一条消息。
发送者运行结果如下:
D:\dev-env\java\jdk1.8.0_181\bin\java.exe ...
Send message: Simple Queue Message, count = 1
Send message: Simple Queue Message, count = 2
Send message: Simple Queue Message, count = 3
Send message: Simple Queue Message, count = 4
Send message: Simple Queue Message, count = 5
Send message: Simple Queue Message, count = 6
消费者运行结果如下:
D:\dev-env\java\jdk1.8.0_181\bin\java.exe ...
Consumer 2 Waiting for messages. To exit press CTRL+C
Consumer 1 Waiting for messages. To exit press CTRL+C
Consumer 1 received message: Simple Queue Message, count = 1
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 2
Consumer 2 work done
Consumer 1 received message: Simple Queue Message, count = 3
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 4
Consumer 2 work done
Consumer 1 received message: Simple Queue Message, count = 5
Consumer 1 work done
Consumer 2 received message: Simple Queue Message, count = 6
Consumer 2 work done
// TODO