在说正题以前先解释一下交换机模式是个笼统的称呼,它不是一个单独的模式(包括了订阅模式,路由模式和主题模式),交换机模式是一个比较经常使用的模式,主要是为了实现数据的同步。java
首先,说一下订阅模式,就和字面上的意思差很少主要就是一个生产者,多个消费者,同一个消息被多个消费者获取,先看一下官网的图示sql
总体执行过程就和图里同样,生产者把消息发送到交换机,而后队列绑定到交换机,消息由交换机发送到队列,每个队列都有一个各自的消费者。这样spa
就实现了一个消息被多个消费者所获取,并且若是有新的消费者加入直接绑定队列到交换机就能够了,大大的下降了系统间的耦合度。还有一点要注意的就是3d
当咱们把消息发送到一个没有队列绑定的交换机时,消息就会丢失,由于消息只能存储在队列,而交换机只作交换,不作存储!code
生产者代码: blog
public class Send { private final static String EXCHANGE_NAME = "exchange_name"; //交换机名称 public static void main(String[] argv) throws Exception { // 获取MQ链接和通道 Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // 声明交换机 channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); // 消息内容 String message = "生产者消息"; channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes()); System.out.println(" 发送 '" + message + "'"); channel.close(); connection.close(); } }
消费者一号代码:队列
public class Recv { private final static String QUEUE_NAME = "test_queue_ex"; private final static String EXCHANGE_NAME = "exchange_name"; public static void main(String[] argv) throws Exception { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // 声明队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); channel.basicQos(1); // 定义队列的消费者 QueueingConsumer consumer = new QueueingConsumer(channel); // 监听队列,手动返回完成 channel.basicConsume(QUEUE_NAME, false, consumer); // 获取消息 while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" 消费者一号 '" + message + "'"); Thread.sleep(10); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } } }
消费者二号代码:路由
public class Recv2 { private final static String QUEUE_NAME = "test_queue_ex2"; private final static String EXCHANGE_NAME = "exchange_name"; public static void main(String[] argv) throws Exception { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); channel.basicQos(1); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(QUEUE_NAME, false, consumer); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println("消费者二号 '" + message + "'"); Thread.sleep(10); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } } }
运行代码以后能够看到get
生产者发送的消息已经存储在了交换机之中。查看绑定关系以下图所示:同步
因此,能够得出结论一个消息被多个消费者所消费。订阅模式也存在着缺陷有时并非全部数据都须要同步,因此用订阅模式来作数据同步并不合理。因而就用到了路由模式。
官网图示以下:
和订阅模式比较相似,只是type变成了direct类型,路由模式也是先由生产者发送消息到交换机,而后在根据绑定键来判断消息发送到哪个交换机。以下图:
和订阅模式的区别就是生产者发送消息时要先声明消息的类型,也就是说消息会被哪类消费者所获取
消费者和生产者保持一个类型的时候,就能够接收到对应生产者所发送的消息了。从而能够过滤掉不须要的消息类型。
主题模式我的感受就和sql语句里的like关键字同样,不用保证消息类型同样,只要保证其类似就能够接收消息了,相比于路由模式,
主题模式匹配率比较低,可是功能确提升了不少,减小了路由key的建立,如图所示:
type变成了topic类型,至于其余方面和路由模式同样就很少说了。