rabbitmq5-发布订阅模式
2018-09-04 本文已影响0人
fkxuexi
前面的几篇博文中讲解的是两个简单的模式,并没有提到exchange交互及这个东西,那么是时候该引入完整的模式了,我们将引入exchange,同时介绍exchange的几种工作的模式
一、发布订阅模式概念及应用场景:
1、概念
发布订阅模式使用的是“fanout”扇出模式,即exchange将忽略routing key把其投递到所有绑定的队列中
2、应用场景:
- 广播:例如通知所有店小二,周五放假
二、关键组件“exchange”:
2.1、exchange的几种模式:
- direct:默认的一种模式,消息分发规则为:消息会被投递到binding key和routing key完全匹配的队列中去
- topic:和direct类似,不过binding key和routing key的匹配规则可以使用正则表达式
- header:将忽略routing key,是使用发送消息是的basicProperties对象中的headers来进行匹配的,headers是一个键值对类型发送消息的header与队列绑定时键值对匹配时,队列绑定交换机时使用x-match,在匹配是有两种模式,①:any只要匹配其中一个就可以,②:all则表示所有的都要完全匹配
- fanout:本节要讲的一种模式。同上面一样,消息投递的时候将忽略routing key,会把接收到的消息投递到所有与之绑定的队列中去
2.2 留一个问题思考一下:
- 1、publishe端的肯定很好解决
- 2、subscriber端的,以及这个消息什么时候被删除,因为不可能一直保存在队列当中的呀
三、把代码呈上来:
3.1、publisher:
public class Publisher {
public static final String EXCHANGE_NAME = "publisher";
public static void main(String[] args) throws IOException, TimeoutException {
Connection conn = ConnUtils.getConn();
Channel channel = conn.createChannel();
BuiltinExchangeType type = BuiltinExchangeType.FANOUT;
boolean durable = true;
boolean autoDelete = false;
/**
* 是否为内部交换机,如果是则不能与外部client直接,通用用于例如死信队列
*/
boolean internal = false;
// 在这里最后一个参数还是不做讲解,在后面高级的部分在做讲解,死信队列、延迟队列、优先级队列
channel.exchangeDeclare(EXCHANGE_NAME,type,durable,autoDelete,internal,null);
// 这个里面我们不指定 routing key,因为没有意义,在fanout模式下会被忽视掉的
channel.basicPublish(EXCHANGE_NAME,"",null,"我假装是你们想要发送的消息".getBytes());
}
}
3.1、subscriber:
这个里面和官方给的代码不一样,如果不声明队列使用官方的形式的话,将会有一个临时的队列,
public class Subscriber01 {
public static final String EXCHANGE_NAME = "publisher";
public static void main(String[] args) throws IOException, TimeoutException {
Connection conn = ConnUtils.getConn();
final Channel channel = conn.createChannel();
channel.queueDeclare("publisher",true,false,false,null);
// 因为routing key会被忽略,所以还是无需指定
// 这个地方queue:队列的名称是需要指定的
channel.queueBind("publisher",EXCHANGE_NAME,"");
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"utf-8"));
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
boolean autoAck = false;
channel.basicConsume("publisher",autoAck,consumer);
}
}
下面我们来回答上面的问题:
在上面的测试中,我们两个订阅者绑定的是同一个队列,结果只有其中的一个subscriber收到了消息,另外一个没有收到,这个是正常的,因为rabbitmq当消费者应答之后,mq会自动的把消息删除,现在我们看一下概念,发布订阅模式指的是:exchange忽略routing key把消息投递到所有的绑定它的队列,并不是说投递到所有的消费者,因此我们前面的假设都是有问题的,这也是我在学习的过程中算是胡思乱想的吧,希望大家能够明悟。
如果有疑问或者是需要交流可以在下面评论也可以扫码进群