Function:
1. Publish subscribe model
2. Routing model
3. Theme model
1 github: source code address
2 rabbitmq02 subproject
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.yzm</groupId> <artifactId>rabbitmq</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> <!-- lookup parent from repository --> </parent> <artifactId>rabbitmq02</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>rabbitmq02</name> <description>Demo project for Spring Boot</description> <dependencies> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Project structure
application.yml
spring: rabbitmq: port: 5672 host: 127.0.0.1 username: guest password: guest listener: simple: acknowledge-mode: auto prefetch: 1
3 publish and subscribe
- In the previous article, producer production messages are sent directly to the queue for storage;
Now it is sent to the switch, and the switch forwards the message to the queue. The switch can forward it to all queues bound to it or to queues conforming to routing rules. The switch itself will not store the message. If no queue is bound, the message will be lost - The switch used for publishing and subscribing is Fanout switch, also known as broadcast switch
Broadcast switch: there is no concept of routing key in the fanout switch. It will send messages to all queues bound to the switch
Create switches, queues
package com.yzm.rabbitmq02.config; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class FanoutRabbitConfig { //queue public static final String QUEUE_A = "queue-a"; public static final String QUEUE_B = "queue-b"; public static final String FANOUT_EXCHANGE = "fanout.exchange"; @Bean public Queue queueA() { return new Queue(QUEUE_A); } @Bean public Queue queueB() { return new Queue(QUEUE_B); } /** * Message switch configuration * Define the switch direct exchange and bind the message queue * name: Switch name * durable: Set whether it is persistent. If it is set to true, the Exchange will be saved and the data will not be lost even if the server is restarted * autoDelete: Set whether to delete automatically. When the last Queue bound to Exchange is deleted, the Exchange will be deleted automatically. In short, if the Exchange is not bound to any Queue, it will be deleted * internal: Set whether RabbitMQ is used internally. The default is false. If it is set to true, it indicates that it is a built-in switch. The client program cannot directly send messages to this switch, but can only route to the switch through the switch. * <p> * Broadcast switch: there is no concept of routing key in the fanout switch. It will send messages to all queues bound to the switch. * Routing switch: the direct switch is relatively simple. The matching rule is: if the routing key matches, the message will be delivered to the relevant queue * Topic switch: topic switch you use the principle of fuzzy matching routing keys to forward messages to the queue */ @Bean public FanoutExchange fanoutExchange() { return ExchangeBuilder.fanoutExchange(FANOUT_EXCHANGE).build(); } /** * Bind message queue to switch * The switch is equivalent to a Map container. The route corresponds to the key and the Queue corresponds to the value * When sending a message, the key in the specified switch can add the message to the corresponding queue */ @Bean public Binding bindingA() { return BindingBuilder.bind(queueA()).to(fanoutExchange()); } @Bean public Binding bindingB() { return BindingBuilder.bind(queueB()).to(fanoutExchange()); } }
producer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.FanoutRabbitConfig; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class FanoutSenderService { private final RabbitTemplate rabbitTemplate; private int count = 1; public FanoutSenderService(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } @Scheduled(fixedDelay = 500, initialDelay = 10000) public void send() { if (count <= 10) { String message = "Hello.........." + count++; rabbitTemplate.convertAndSend(FanoutRabbitConfig.FANOUT_EXCHANGE, "", message); System.out.println(" [ producer ] Sent ==> '" + message + "'"); } } }
consumer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.FanoutRabbitConfig; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class FanoutReceiverService { private int countA = 1; private int countB = 1; private int countB_2 = 1; @RabbitListener(queues = FanoutRabbitConfig.QUEUE_A) public void receiveA(String message) { try { System.out.println(" [ consumer@A number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@A number ] Dealt with: " + countA++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = FanoutRabbitConfig.QUEUE_B) public void receiveB(String message) { try { System.out.println(" [ consumer@B number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@B number ] Dealt with: " + countB++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = FanoutRabbitConfig.QUEUE_B) public void receiveB_2(String message) { try { System.out.println(" [ consumer@B_2 number ] Received ==> '" + message + "'"); Thread.sleep(2000); System.out.println(" [ consumer@B_2 number ] Dealt with: " + countB_2++); } catch (Exception e) { e.printStackTrace(); } } }
Start project
The operation results are as follows
The producer produces 10 messages and sends them to the switch, which forwards the messages to the queues A and B bound to it respectively;
Queues A and B get 10 messages with the same content. Queue A has only one consumer A, so consumer A processes all messages
Queue B has two consumers B, B_2. The distribution mode is based on capacity, so consumer B handles more
4 routing model
Routing switch: the direct switch is relatively simple. The matching rule is: if the routing key matches completely, the message will be delivered to the relevant queue
Create switches, queues
package com.yzm.rabbitmq02.config; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class DirectRabbitConfig { //queue public static final String QUEUE_C = "queue-c"; public static final String QUEUE_D = "queue-d"; //Routing key public static final String DIRECT_C = "direct.c"; public static final String DIRECT_D = "direct.d"; public static final String DIRECT_D2 = "direct.dcd"; public static final String DIRECT_EXCHANGE = "direct.exchange"; @Bean public Queue queueC() { return new Queue(QUEUE_C); } @Bean public Queue queueD() { return new Queue(QUEUE_D); } /** * Message switch configuration * Define the switch direct exchange and bind the message queue * name: Switch name * durable: Set whether it is persistent. If it is set to true, the Exchange will be saved and the data will not be lost even if the server is restarted * autoDelete: Set whether to delete automatically. When the last Queue bound to Exchange is deleted, the Exchange will be deleted automatically. In short, if the Exchange is not bound to any Queue, it will be deleted * internal: Set whether RabbitMQ is used internally. The default is false. If it is set to true, it indicates that it is a built-in switch. The client program cannot directly send messages to this switch, but can only route to the switch through the switch. * <p> * Broadcast switch: there is no concept of routing key in the fanout switch. It will send messages to all queues bound to the switch. * Routing switch: the direct switch is relatively simple. The matching rule is: if the routing key matches completely, the message will be delivered to the relevant queue * Topic switch: topic switch you use the principle of fuzzy matching routing keys to forward messages to the queue */ @Bean public DirectExchange directExchange() { return ExchangeBuilder.directExchange(DIRECT_EXCHANGE).build(); } /** * Bind message queue to switch * The switch is equivalent to a Map container. The route corresponds to the key and the Queue corresponds to the value * When sending a message, the key in the specified switch can add the message to the corresponding queue */ @Bean public Binding bindingC() { return BindingBuilder.bind(queueC()).to(directExchange()).with(DIRECT_C); } @Bean public Binding bindingD() { return BindingBuilder.bind(queueD()).to(directExchange()).with(DIRECT_D); } @Bean public Binding bindingD2() { return BindingBuilder.bind(queueD()).to(directExchange()).with(DIRECT_D2); } }
producer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.DirectRabbitConfig; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class DirectSenderService { private final RabbitTemplate rabbitTemplate; private int count = 0; public DirectSenderService(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } @Scheduled(fixedDelay = 500, initialDelay = 10000) public void send_1() { count++; if (count <= 30) { String message = "Hello.........." + count; System.out.println(" [ producer ] Sent ==> '" + message + "'"); if (count % 3 == 0) { rabbitTemplate.convertAndSend(DirectRabbitConfig.DIRECT_EXCHANGE, DirectRabbitConfig.DIRECT_C, message); } else if (count % 3 == 1) { rabbitTemplate.convertAndSend(DirectRabbitConfig.DIRECT_EXCHANGE, DirectRabbitConfig.DIRECT_D, message); } else { rabbitTemplate.convertAndSend(DirectRabbitConfig.DIRECT_EXCHANGE, DirectRabbitConfig.DIRECT_D2, message); } } } }
consumer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.DirectRabbitConfig; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class DirectReceiverService { private int countC = 1; private int countD = 1; private int countD_2 = 1; @RabbitListener(queues = DirectRabbitConfig.QUEUE_C) public void receiveC(String message) { try { System.out.println(" [ consumer@C number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@C number ] Dealt with: " + countC++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = DirectRabbitConfig.QUEUE_D) public void receiveD(String message) { try { System.out.println(" [ consumer@D number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@D number ] Dealt with: " + countD++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = DirectRabbitConfig.QUEUE_D) public void receiveD_2(String message) { try { System.out.println(" [ consumer@D_2 number ] Received ==> '" + message + "'"); Thread.sleep(2000); System.out.println(" [ consumer@D_2 number ] Dealt with: " + countD_2++); } catch (Exception e) { e.printStackTrace(); } } }
In order not to affect the test of routing mode, turn off the timer of publish subscribe mode
Start project
The operation results are as follows:
We created two queues C and D, C has one routing key and D has two routing keys;
The producer produces 30 messages, which are sent to the switch evenly through the routing key. The switch allocates 10 messages to queue C and 20 messages to queue D according to the routing key;
From the results of operation, the expected results are indeed achieved
5 theme mode (wildcard mode)
Topic switch: topic switch uses the principle of fuzzy matching routing key to forward messages to the queue
Create switches, queues
package com.yzm.rabbitmq02.config; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class TopicRabbitConfig { //queue public static final String QUEUE_E = "queue-e"; public static final String QUEUE_F = "queue-f"; public static final String QUEUE_G = "queue-g"; public static final String TOPIC_EXCHANGE = "topic.exchange"; //Two special characters * and # are used for fuzzy matching, where * is used to match one word and # is used to match multiple words (can be zero) public static final String TOPIC_E = "topic.*"; public static final String TOPIC_F = "topic.#"; public static final String TOPIC_G = "topic.*.key"; @Bean public Queue queueE() { return new Queue(QUEUE_E); } @Bean public Queue queueF() { return new Queue(QUEUE_F); } @Bean public Queue queueG() { return new Queue(QUEUE_G); } /** * Message switch configuration * Define the switch direct exchange and bind the message queue * name: Switch name * durable: Set whether it is persistent. If it is set to true, the Exchange will be saved and the data will not be lost even if the server is restarted * autoDelete: Set whether to delete automatically. When the last Queue bound to Exchange is deleted, the Exchange will be deleted automatically. In short, if the Exchange is not bound to any Queue, it will be deleted * internal: Set whether RabbitMQ is used internally. The default is false. If it is set to true, it indicates that it is a built-in switch. The client program cannot directly send messages to this switch, but can only route to the switch through the switch. * <p> * Broadcast switch: there is no concept of routing key in the fanout switch. It will send messages to all queues bound to the switch. * Routing switch: the direct switch is relatively simple. The matching rule is: if the routing key matches, the message will be delivered to the relevant queue * Topic switch: topic switch uses the principle of fuzzy matching routing key to forward messages to the queue */ @Bean public TopicExchange topicExchange() { return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE).build(); } /** * Bind message queue to switch * The switch is equivalent to a Map container. The route corresponds to the key and the Queue corresponds to the value * When sending a message, the key in the specified switch can add the message to the corresponding queue */ @Bean public Binding bindingE() { return BindingBuilder.bind(queueE()).to(topicExchange()).with(TOPIC_E); } @Bean public Binding bindingF() { return BindingBuilder.bind(queueF()).to(topicExchange()).with(TOPIC_F); } @Bean public Binding bindingG() { return BindingBuilder.bind(queueG()).to(topicExchange()).with(TOPIC_G); } }
producer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.TopicRabbitConfig; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class TopicSenderService { private final RabbitTemplate rabbitTemplate; private int count = 0; public TopicSenderService(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } @Scheduled(fixedDelay = 500, initialDelay = 10000) public void send_1() { count++; if (count <= 30) { String message = "Hello.........." + count; System.out.println(" [ producer ] Sent ==> '" + message + "'"); if (count % 3 == 0) { rabbitTemplate.convertAndSend(TopicRabbitConfig.TOPIC_EXCHANGE, "topic.yzm", message); } else if (count % 3 == 1) { rabbitTemplate.convertAndSend(TopicRabbitConfig.TOPIC_EXCHANGE, "topic.yzm.yzm", message); } else { rabbitTemplate.convertAndSend(TopicRabbitConfig.TOPIC_EXCHANGE, "topic.yzm.key", message); } } } }
consumer
package com.yzm.rabbitmq02.service; import com.yzm.rabbitmq02.config.TopicRabbitConfig; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class TopicReceiverService { private int countE = 1; private int countF = 1; private int countG = 1; @RabbitListener(queues = TopicRabbitConfig.QUEUE_E) public void receiveE(String message) { try { System.out.println(" [ consumer@E number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@E number ] Dealt with: " + countE++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = TopicRabbitConfig.QUEUE_F) public void receiveF(String message) { try { System.out.println(" [ consumer@F number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@F number ] Dealt with: " + countF++); } catch (Exception e) { e.printStackTrace(); } } @RabbitListener(queues = TopicRabbitConfig.QUEUE_G) public void receiveG(String message) { try { System.out.println(" [ consumer@G number ] Received ==> '" + message + "'"); Thread.sleep(1000); System.out.println(" [ consumer@G number ] Dealt with: " + countG++); } catch (Exception e) { e.printStackTrace(); } } }
Turn off the front timer
Start project
The operation results are as follows:
Analyze the number of messages received by E, F and G queues
The operation results are consistent with the expected results