消息队列之订阅模式
1、订阅模式
- 前面我们学到了简单、轮询、公平分发等
- 在上面这几种模式下,我们的消息无法重复消费信息
- 为了重复消费信息我们使用了交换机(
exchange
)的fanout模式
2、交换机(exchange)的fanout
为了使我们可以重复的使用消息,我们就要用到交换机的fanout模式(发布订阅)
P是生产者,X交换机,红色是消息队列
生产者将消息发送给交换机,交换机再将信息发送给与自己绑定了的消息队列
3、生产者
在定义的时候我们不再声明队列,而声明一个交换机,将信息发送给交换机
public class Send {
private static final String EXCHANGE_NAME= "test.exchange";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"fanout", true);//开启持久化的交换机
for (int i=0;i<10;i++){
String msg = "hello ps:"+i;
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
System.out.println("Send:" + msg);
}
channel.close();
connection.close();
}
}
4、消费者
消费者声明一个队列并将其与交换机绑定
public class WorkFairGet1 {
private static final String QUEUE_NAME= "test_exchange_queue1";
private static final String EXCHANGE_NAME= "test.exchange";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
//绑定到交换机
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
//channel.basicQos(1)指该消费者在接收到队列里的消息但没有返回确认结果之前,
// 队列不会将新的消息分发给该消费者。队列中没有被消费的消息不会被删除,还是存在于队列中
channel.basicQos(1);//保证一次只分发一个
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
String msg = new String(body,"utf-8");
System.out.println("接受转换机的消息队列1:"+msg);
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//手动回执消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
boolean autoACK = false;
channel.basicConsume(QUEUE_NAME,autoACK,consumer);
}
}