RabbitMQ基本概念和交换机的使用

RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议,在完全不同的应用之间共享数据,RabbirMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。

AMQP高级消息队列协议

AMQP全称:Advanced Message Queuing Protocol

AMQP翻译:高级消息队列协议

AMQP定义:是具有现代特征的二进制协议,是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

AMQP协议模型:生产者应用服务端-------》将消息扔到server端(rabbitmq的节点)上,Virtual host虚拟主机,其实就是一个上层路由逻辑的概念,Exchange也就是更上一级的AMQP协议的核心。

生产者将消息投递到Server的Exchange交换机上。(消息投递要经过服务连接用户名,密码,ip地址,在经过虚拟主机Virtual host,最后投递到具体的Exchange)。

消费者应用服务端-------》监听Message Queue(消息队列)。

Exchange和Message Queue又有一个绑定关系。

AMQP核心概念

Server:又称Broker,接受客户端的连接,实现AMQP实体服务

Connection:连接,应用程序与Broker的网络连接

Channel:网络通信,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道,消息流转,清空消息,添加用户等)。客户端可建立多个Channel,每个Channel代表一个会话任务(拿到连接,创建channel)

Message:消息,服务器和应用程序之间传送的数据,由Properties和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟投递等高级特性,Body则是消息体内容

Virtual host:虚拟主机,用于进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue,同一个Virtual host里面不能有相同名称的Exchange或者Queue  

Exchange:交换机,接收消息,根据路由键(routing key)转发消息到绑定的队列上

Binding:绑定,Exchange和Queue之间的虚拟连接,binding中可以包含routing key

Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息

Queue:也成为Message Queue,消息队列,保存消息并将他们转发给消费者

RabbitMQ的整体架构

左P:生产者

右P:消费者

中间:Server端

绿X:交换机

红:队列

生产者将消息投递到交换机上,一个交换机可以绑定多个消息队列,交换机有一个路由策略,指定两个属性:

1、消息发送哪个exchange

2、消息带上路由key,exchange和队列绑定关系,通过路由key将消息路由到指定队列上,发送给消费者。

基本概念

Virtual Host

虚拟主机,用于进行逻辑隔离,最上层的消息路由
一个Virtual Host里面可以有若干个Exchange和Queue
同一个Virtual Host不能有相同名称的Exchange和Queue

Binding

绑定,Exchange和Exchange、Queue之间的连接
Binding中可以包含RoutingKey或者参数

Queue

消息队列,实际存储消息数据
Durability:是否持久化,Durable:是,Transient:否
Auto Delete:如选yes,代表当最后一个监听被移除之后,该Queue会自动被删除

Message

服务器和应用程序之间传送的数据,本质上是一段数据,有Properties和Payload(Body)组成
常用属性:delivery mode、headers(自定义属性)
其他属性:content_type、content_encoding(字符集)、priority(消息优先级0-9,从小到大,优先级越来越高)、correlation_id(消息唯一id)、reply_to(重回队列,返回哪个队列)、expiration(消息过期时间)、message_id(消息id)timestamp(时间戳)、type、user_id、app_id、cluster_id

消费者

public class Consumer {
	public static void main(String[] args) throws Exception {
		
		//1 创建一个ConnectionFactory, 并进行配置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		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 获取消息
			Delivery delivery = queueingConsumer.nextDelivery();
			String msg = new String(delivery.getBody());
			System.err.println("消费端: " + msg);
			Map<String, Object> headers = delivery.getProperties().getHeaders();
			System.err.println("headers get my1 value: " + headers.get("my1"));
			//Envelope envelope = delivery.getEnvelope();
		}
	}
}

生产者

public class Procuder {
	public static void main(String[] args) throws Exception {
		//1 创建一个ConnectionFactory, 并进行配置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 通过连接工厂创建连接
		Connection connection = connectionFactory.newConnection();
		
		//3 通过connection创建一个Channel
		Channel channel = connection.createChannel();
		
		Map<String, Object> headers = new HashMap<>();
		headers.put("my1", "111");
		headers.put("my2", "222");
		
		AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
				.deliveryMode(2)
				.contentEncoding("UTF-8")
				.expiration("10000")
				.headers(headers)
				.build();
		
		//4 通过Channel发送数据
		for(int i=0; i < 5; i++){
			String msg = "Hello RabbitMQ!";
			//1 exchange   2 routingKey
			channel.basicPublish("", "test001", properties, msg.getBytes());
		}
		//5 记得要关闭相关的连接
		channel.close();
		connection.close();
	}
}

Exchange(交换机)

属性

  • Name:交换机名称
  • Type:交换机类型
  • Durability:是否需要持久化
  • Auto Delete:当最后一个绑定在该Exchange上的队列删除后,自动删除该Exchange
  • Intenal:当前Exchange是否用于RabbitMQ内部使用,默认false
  • Arguments:扩展参数,用于扩展AMQP协议定制化使用

Direct Exchange

所有发送到Direct Exchange的消息会被转发到RoutingKey指定的Queue

Direct模式可以使用RabbitMQ自带的Exchange:Default Exchange,所以不需要将Exchange进行任何绑定操作,消息传递时,RoutingKey必须完全匹配才能被队列接收,否则会被抛弃。

消费者

public class Consumer4DirectExchange {

	public static void main(String[] args) throws Exception {
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_direct_exchange";
		String exchangeType = "direct";
		String queueName = "test_direct_queue";
		String routingKey = "test.direct";
		
		//表示声明了一个交换机
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		//表示声明了一个队列
		channel.queueDeclare(queueName, false, false, false, null);
		//建立一个绑定关系:
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //创建消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //参数:队列名称、是否自动ACK、Consumer
        channel.basicConsume(queueName, true, consumer);  
        //循环获取消息  
        while(true){  
            //获取消息,如果没有消息,这一步将会一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

生产者

public class Producer4DirectExchange {
	public static void main(String[] args) throws Exception {
		
		//1 创建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 创建Connection
		Connection connection = connectionFactory.newConnection();
		//3 创建Channel
		Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_direct_exchange";
		String routingKey = "test.direct";
		//5 发送
		
		String msg = "Hello World RabbitMQ 4  Direct Exchange Message";
		channel.basicPublish(exchangeName, routingKey , null , msg.getBytes());
	}
}

Topic Exchange

可以使用通配符进行模糊匹配

  • #:匹配一个或多个词
  • *:匹配一个词

消费者

public class Consumer4TopicExchange {

	public static void main(String[] args) throws Exception {
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_topic_exchange";
		String exchangeType = "topic";
		String queueName = "test_topic_queue";
		//String routingKey = "user.*";
		String routingKey = "user.*";
		// 1 声明交换机 
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		// 2 声明队列
		channel.queueDeclare(queueName, false, false, false, null);
		// 3 建立交换机和队列的绑定关系:
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //创建消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //参数:队列名称、是否自动ACK、Consumer
        channel.basicConsume(queueName, true, consumer);  
        //循环获取消息  
        while(true){  
            //获取消息,如果没有消息,这一步将会一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

生产者

public class Producer4TopicExchange {
	public static void main(String[] args) throws Exception {
		//1 创建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 创建Connection
		Connection connection = connectionFactory.newConnection();
		//3 创建Channel
		Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_topic_exchange";
		String routingKey1 = "user.save";
		String routingKey2 = "user.update";
		String routingKey3 = "user.delete.abc";
		//5 发送
		String msg = "Hello World RabbitMQ 4 Topic Exchange Message ...";
		channel.basicPublish(exchangeName, routingKey1 , null , msg.getBytes()); 
		channel.basicPublish(exchangeName, routingKey2 , null , msg.getBytes()); 	
		channel.basicPublish(exchangeName, routingKey3 , null , msg.getBytes()); 
		channel.close();  
        connection.close();  
	}
}

Fanout Exchange

不处理路由键,发送到交换机的消息会被转发到与该交换机绑定的所有队列上,这种方式转发消息的速度最快

消费者

public class Consumer4FanoutExchange {
	public static void main(String[] args) throws Exception {
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_fanout_exchange";
		String exchangeType = "fanout";
		String queueName = "test_fanout_queue";
		String routingKey = "";	//不设置路由键
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		channel.queueDeclare(queueName, false, false, false, null);
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //durable 是否持久化消息
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //参数:队列名称、是否自动ACK、Consumer
        channel.basicConsume(queueName, true, consumer); 
        //循环获取消息  
        while(true){  
            //获取消息,如果没有消息,这一步将会一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

生产者:

public class Producer4FanoutExchange {
	public static void main(String[] args) throws Exception {
		
		//1 创建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 创建Connection
		Connection connection = connectionFactory.newConnection();
		//3 创建Channel
		Channel channel = connection.createChannel();  
		//4 声明
		String exchangeName = "test_fanout_exchange";
		//5 发送
		for(int i = 0; i < 10; i ++) {
			String msg = "Hello World RabbitMQ 4 FANOUT Exchange Message ...";
			channel.basicPublish(exchangeName, "", null , msg.getBytes()); 			
		}
		channel.close();  
        connection.close();  
	}
}
posted @ 2020-04-19 19:51  tianqibucuo  阅读(619)  评论(0编辑  收藏  举报