1.简介
RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue protocol)的开源实现。AMQP高级消息队列,说白了就是一个开源的消息中间件。它能解决不同组件、模块、系统间消息通信。
2.系统架构
RabbitMQ Server: 也叫broker server,存储消息的地方
Producer:数据的发送方
Consumer:数据的接收方
Connection: 就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。
Channels: 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。
那么,为什么使用Channel,而不是直接使用TCP连接?
对于OS来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。
Message:消息。服务器和应用程序之间传递的数据,本质上就是一段数据,由Properties和Body组成。
Exchange:交换机。接收消息,根据路由键转发消息到绑定的队列。
Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key。
Routing key:一个虚拟地址,虚拟机可用它来确定如何路由一个特定消息。
Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者。
Virtual Host:其实是一个虚拟概念。类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,可以用来隔离Exchange和Queue。,同一个Virtual Host里面不能有相同名称的Exchange和Queue。但是权限控制的最小粒度是Virtual Host。(下面会讲到)
3、图解
1. 信息生产者将消息(message)发送到exchange
2. exchange接受消息之后,负责将其路由到具体的队列中
3. Bindings负责连接exchange和队列(queue)
4. 消息到达队列(queue),然后等待被消息接收端处理
5. 消息接收端处理消息
Exchanges有三种类型:direct, fanout,topic。 每个实现了不同的路由算法(routing algorithm)。
Direct exchange: 如果 routing key 匹配, 那么Message就会被传递到相应的queue中。其实在queue创建时,它会自动的以queue的名字作为routing key来绑定那个exchange。
Fanout exchange: 会向响应的queue广播。
Topic exchange: 对key进行模式匹配,比如ab*可以传递到所有ab*的queue。
Consumer和Procuder都可以通过 queue.declare 创建queue。如果queue已经存在,也不会报错。如果没有,要么发送不了消息,要么取不到消息,所以还是都创建吧。
Bindings就是将通过Exchange将queue和routing keys绑定。
总结:生产者将消息发送到Exchange交换机的,不是发送到Queue上的,生产者不知道消息是谁消费,有哪些消费者消费。Exchange根据一定的路由规则将消息转发到Queue。
消费者是监听队列的,不知道是哪个生产者发送的
4.具体代码
添加maven 依赖
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>3.6.5</version> </dependency>
消费者
package com.flying.rabbitmq.quickstart; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.QueueingConsumer; import java.io.IOException; import java.util.concurrent.TimeoutException; public class Consumer { public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //创建connectionFactory 并进行配置 ConnectionFactory connectionFactory=new ConnectionFactory(); connectionFactory.setHost("127.0.0.1"); connectionFactory.setPort(5672); connectionFactory.setVirtualHost("/"); //2.通过连接工厂创建连接 Connection connection=connectionFactory.newConnection(); //3.通过connection 创建一个channel 通道 Channel channel=connection.createChannel(); //4 声明(创建)一个队列 String queueName = "test001"; channel.queueDeclare(queueName,true,false,false,null); //5.声明一个消费者 QueueingConsumer queueingConsumer=new QueueingConsumer(channel); //6.设置Channel channel.basicConsume(queueName,true,queueingConsumer); while (true){ //7.获取消息 QueueingConsumer.Delivery delivery=queueingConsumer.nextDelivery(); String msg=new String(delivery.getBody()); System.err.println("消费端"+msg); } } }
生产端
package com.flying.rabbitmq.quickstart; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; public class Producer { public static void main(String[] args) throws IOException, TimeoutException { //创建connectionFactory 并进行配置 ConnectionFactory connectionFactory=new ConnectionFactory(); connectionFactory.setHost("127.0.0.1"); connectionFactory.setPort(5672); connectionFactory.setVirtualHost("/"); //2.通过连接工厂创建连接 Connection connection=connectionFactory.newConnection(); //3.通过connection 创建一个channel 通道 Channel channel=connection.createChannel(); //4.通过Channel 发送数据 for(int i=0; i < 5;i++){ String msg="Hello rabbitmq"; channel.basicPublish("","test001",null,msg.getBytes()); } //5 记得要关闭相关的连接 channel.close(); connectionFactory.clone(); } }
运行结果