消息訂閱發佈
- 一個生產者,多個消費者
- 每個消費者都有自己的隊列
- 生產者,沒有直接把消息發送到隊列,而是先發送到交換機
- 每個隊列都要綁定到交換機
- 生產者發送的消息 經過交換機,到達隊列,就能實現一個消息被多個消費者消費
話不多說,直接擼代碼:
老套路,首先還是生產者:
public class Send {
private static final String EXCHANGE_NAME = "test_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitConnection.getConnection(); //看前面文章寫的工具類
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); //聲明exchange,這裏爲什麼是fanout待會下面解釋
//send a msg
String msg = "hello exchange";
channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
System.out.println("send:"+msg);
channel.close();
connection.close();
}
}
消費者1:
public class ReceiveOne {
private static final String QUEUE_NAME = "receive1_queue"; //這裏我們重新申請一個新的隊列
private static final String EXCHANGE_NAME = "test_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitConnection.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicQos(1);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); //這裏需要綁定exchange,其他的和前面的work_queue是一樣的
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [ConsumerOne is] Received '" + message + "'");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); //這裏是手動應答
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, deliverCallback, consumerTag -> { });
}
}
消費者2:
public class ReceiveTwo {
private static final String QUEUE_NAME = "receive2_queue";
private static final String EXCHANGE_NAME = "test_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitConnection.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicQos(1);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [ConsumerTwo is] Received '" + message + "'");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); //這裏是手動應答
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, deliverCallback, consumerTag -> { }); }
}
我們啓動send和兩個消費者,消費者同時消費,同一個消息,
再回到控制檯,發現綁定了兩個隊列:
關於send中那個fanout參數,有必要講一下,它表示不處理路由鍵,具體路由鍵是怎麼回事,可參考下面這個博客:
至此消息訂閱發佈模式結束。