Eight, RabbitMQ of themes (Topics)

First, the model

Themes model diagram

  • P (Producer): Manufacturer - Send message
  • X (Exchange): Switch - Accept message sent by the producer on the one hand, on the other hand the push message to the queue
  • Q (Queue): a message queue (FIG red squares) - stored message
  • C (consumer): Consumers - receive messages 
  • Binding: Bind - binding relationship between the switch and the queue
  • Routing Key: routing keys - have this message and binding property, the switch push messages, will find itself consistent with the routing message queue push button in the queues that are bound in

    Themes (Topics): send a message as well as switches and queue binding relationship are required to set up self-routing key, and bindings (Binding) routing key support wildcards , after the producer sends a message to the switch, the switch in queues that are bound to find routing keys of the message routing keys to match the queue to the push message. If there is no match, then the message is lost.

通配符说明:

*:匹配一个字符
#:匹配一个或多个字符


注意:
1、若队列与交换机的Binding中Routing Key不包含*和#,则表示相等队列推送,类似于直连交换机(Direct Exchange);
2、若队列与交换机的Binding中Routing Key为#或#.#,则表示全部队列推送,类似于扇形交换机(Fanout Exchange)。

    Model interpretation

  • Binding between the switch and the key queue are set to the self-routing, and the routing carried binding key support wildcards;
  • The message itself also need to set up routing keys;
  • When the switch for an authentication message routing keys and push message routing keys binding phase matching will push.

    Note: routing mode (the Routing) need to switch (Exchange) type is defined as "Topic".

Two, Topic Exchange (theme switch)

    1, model

Theme switch model diagram

    2, meaning 

    Theme switch (Topic Exchange) will look at all of their binding relationship according to the message carried by routing keys (Routing Key), and routing key messages that match the queue to push the message.

   3, different from the direction switch (Direct Exchange) of

    3.1, direction switch, the key binding relationship routing queue and the switch does not support wildcards, but the theme switches support;

    3.2, direction switch, the message needs to be pushed to the queue message routing keys bind identical, but the topic is the switch case relative wildcard match line.

Three, Java programming

    1, jar introduced AMQP protocol packet, and creating tools RabbitMQ connection, see three, the simple RabbitMQ queue (the Simple Queue) ;

    2, create message sent by the producer;

package com.rabbitMQ.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitMQ.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * 主题模式-生产者
 * *:代表一个任意字符
 * #:代表一个或多个任意字符
 * @author zhoujin
 * @data 2019-1-23
 */
public class TopicProducer {
	
	private static final String EXCHANGE_NAME = "exchange_topic";
	
	private static final String TOPIC_ERROR = "message.error";
	private static final String ERROR_MESSAGE = "This is topic MQ, routing key is message.error!";
	
	private static final String TOPIC_INFO = "message.info";
	private static final String INFO_MESSAGE = "This is topic MQ, routing key is message.info!";

	public static void main(String[] args) {
		Connection conn = null;
		Channel channel = null;
		try {
			// 1.获取连接
			conn = ConnectionUtils.getConnection();
			// 2.从连接中获取通道
			channel = conn.createChannel();
			// 3.声明交换机
			channel.exchangeDeclare(EXCHANGE_NAME, "topic");
			// 4.发送消息
			String message = ERROR_MESSAGE;
			channel.basicPublish(EXCHANGE_NAME, TOPIC_ERROR, null, message.getBytes());
			System.out.println("======================= Topic MQ send message end! 【Content:" + message + "】 =======================");
			
			message = INFO_MESSAGE;
			channel.basicPublish(EXCHANGE_NAME, TOPIC_INFO, null, message.getBytes());
			System.out.println("======================= Topic MQ send message end! 【Content:" + message + "】 =======================");
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		} finally {
			// 7.关闭连接
			try {
				ConnectionUtils.closeConnection(channel, conn);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (TimeoutException e) {
				e.printStackTrace();
			}
		}
	}
	
}

   3. Create a consumer 1 receives a message;

package com.rabbitMQ.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitMQ.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;

/**
 * 主题模式-第一个消费者
 * *:代表一个任意字符
 * #:代表一个或多个任意字符
 * @author zhoujin
 * @data 2019-1-23
 */
public class TopicFirstConsumer {
	
	private static final String QUEUE_NAME = "queue_topic_first";
	private static final String EXCHANGE_NAME = "exchange_topic";
	
	public static void main(String[] args) {
		try {
			// 1.获取连接
			Connection conn = ConnectionUtils.getConnection();
			// 2.从连接中获取通道
			final Channel channel = conn.createChannel();
			// 3.声明队列
			channel.queueDeclare(QUEUE_NAME, false, false, false, null);
			// 4.将队列绑定到交换机上
			channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "#.info");
			// 5.保证一次只接收一条消息
			channel.basicQos(1);
			// 6.创建消费者
			DefaultConsumer consumer = new DefaultConsumer(channel){
				
				@Override
				public void handleDelivery(String consumerTag,
						Envelope envelope, BasicProperties properties,
						byte[] body) throws IOException {

					String message = new String(body, "UTF-8");
					System.out.println("======================= First topic(#.info) consumer received a message! 【Content:" + message + "】 =======================");
					
					// 休眠,模拟业务处理
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						// 7.手动发送反馈回执
						channel.basicAck(envelope.getDeliveryTag(), false);
					}
					
				}
				
			};
			// 8.监听队列(关闭自动反馈,即第二个参数为false)
			channel.basicConsume(QUEUE_NAME, false, consumer);
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
	}

}

    4. Create a Consumer 2 receives the message.

package com.rabbitMQ.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitMQ.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;

/**
 * 主题模式-第二个消费者
 * *:代表一个任意字符
 * #:代表一个或多个任意字符
 * @author zhoujin
 * @data 2019-1-23
 */
public class TopicSecondConsumer {
	
	private static final String QUEUE_NAME = "queue_topic_second";
	private static final String EXCHANGE_NAME = "exchange_topic";
	
	public static void main(String[] args) {
		try {
			// 1.获取连接
			Connection conn = ConnectionUtils.getConnection();
			// 2.从连接中获取通道
			final Channel channel = conn.createChannel();
			// 3.声明队列
			channel.queueDeclare(QUEUE_NAME, false, false, false, null);
			// 4.将队列绑定到交换机上
			channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "message.#");
			// 5.保证一次只接收一条消息
			channel.basicQos(1);
			// 6.创建消费者
			DefaultConsumer consumer = new DefaultConsumer(channel){
				
				@Override
				public void handleDelivery(String consumerTag,
						Envelope envelope, BasicProperties properties,
						byte[] body) throws IOException {
					
					String message = new String(body, "UTF-8");
					System.out.println("======================= Second topic(message.#) consumer received a message! 【Content:" + message + "】 =======================");
					
					// 休眠,模拟业务处理
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						// 7.手动发送反馈回执
						channel.basicAck(envelope.getDeliveryTag(), false);
					}
					
				}
				
			};
			// 8.监听队列(关闭自动反馈,即第二个参数为)
			channel.basicConsume(QUEUE_NAME, false, consumer);
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
	}

}

    Note: If only producer in the defined Switches code, but not defined in the consumer queue or queue defined but with the switch to bind, compile and run the program are not being given, but the message will be lost. Because the switch does not have the ability to store messages, RabbitMQ only has the ability to store messages in the queue.

Fourth, run the code and console output

    1, Run producer code - defines the switch;

    ① Why here need to run the code producer?

        Because you need to define the switch in the producer. If the consumer first start, it will error prompted "no exchange" error because the switch is undefined!

    ② why the message sent by the producer lost?

        Yet because the queues that are bound, and the switch itself does not have a function of storing the message, and therefore lead to message loss.

    2, running two consumer code;

    2.1, see the queue in the Web management page binding information;

Web page to view the queue binding information management

    3, run producer code again - sending a message.

    3.1, producers console output;

Producer console output

    3.2, the first consumer (# .info) console output;

The first consumer (# .info) console output

    3.3, the second consumer (message. #) Console output

The second consumer (message. #) Console output

 


Published 47 original articles · won praise 16 · views 70000 +

Guess you like

Origin blog.csdn.net/zorro_jin/article/details/86658977