An article takes you to use SpringBoot to integrate RabbitMQ

One, know RabbitMQ

RabbitMQ is introduced with AMQP protocol:

(1) RabbitMQ is an open source message broker and queue server, used to share data between completely different applications through common protocols. The bottom layer of RabbitMQ is written in Erlang language, and RabbitMQ is based on the AMQP protocol.
(2) RabbitMQ can not only be written using the java client, but also other languages ​​(python, php, etc...), it provides a rich API

Advantages of RabbitMQ:

(1) Open source, excellent performance, stability guarantee
(2) Perfect integration with SpringAMQP, rich API (Spring provides a framework based on RabbitMQ, called AMQP framework) This framework not only presents the native RabbitMQ, but also provides Rich and expandable APIs help developers to better apply
(3) Rich cluster mode, expression configuration, HA mode, mirror queue model
description: (to ensure high reliability and availability in advance without data loss) universal use The mirror queue mode
(4) AMQP full name: Advanced Message Queuing Protocl AMQP translated: Advanced Message Queuing Protocol

Two, install RabbitMQ

Here to facilitate the installation of RabbitMQ on docker
(1) First search for the installation command of RabbitMQ: https://hub.docker.com/_/rabbitmq

 docker run -d --hostname my-rabbit --name some-rabbit rabbitmq:3-management

Insert picture description here
Successful installation:

Insert picture description here

For the mapped ports, you need to pay attention to two: 15672 and 5672, where 15672 is the management port and 5672 is the communication port

Insert picture description here
You can see that the host mapping port corresponding to docker container 15672 is 32771,

Insert picture description here
The default username and password are both guest

Three, SpringBoot integrates RabbitMQ

1. Add dependencies

Insert picture description here

2. Configure application.properties

Note that the port selection here is 32781, the port corresponding to the rabbitmq container is 5672, select the communication port, and do not choose the management port

Insert picture description here

spring.rabbitmq.host=192.168.245.133
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=32781

3. Direct exchange mode

For direct exchange mode, please refer to: https://blog.csdn.net/fakerswe/article/details/81508963

The so-called "directly connected to the exchange" means: the message delivered by the Producer (producer) is forwarded by DirectExchange (switch) to a specific Queue (queue) bound by routingkey, the message is put into the queue, and the Consumer subscribes to the message from the Queue

Here the specific parameters of a queue is routingKeycontrolled, this parameter message is delivered to the queue

Insert picture description here

The core idea of ​​the RabbitMQ message model: The producer will send the message to the RabbitMQ exchange center (Exchange). One side of the Exchange is the producer, and the other side is one or more queues. The Exchange determines a message Life cycle-sent to some queues, or discarded directly.

(1) Configure RabbitDirectConfig

@Configuration
public class RabbitDirectConfig {
    
    

    public final static String DIRECTNAME = "yolo-direct";

    // 消息队列
    @Bean
    Queue queue() {
    
    
        return new Queue("hello.yolo");
    }

    @Bean
    DirectExchange directExchange() {
    
    
        return new DirectExchange(DIRECTNAME, true, false);
    }
    // 将 queue 和 directExchange 绑定到一起
    @Bean
    Binding binding() {
    
    
        return BindingBuilder.bind(queue()).to(directExchange()).with("direct");
    }
}

(2) Consumer

@Component
public class DirectReceiver {
    
    
    // 监听队列
    @RabbitListener(queues = "hello.yolo")
    public void handler1(String msg) {
    
    
        System.out.println("handler1>>>" + msg);
    }
}

(3) Test: Producer

 	@Autowired
    RabbitTemplate rabbitTemplate;
    @Test
    public void contextLoads() {
    
    
        //将消息转发到 routingKey 为 hello.yolo 的队列,对应 DirectReceiver 的监听队列名
        rabbitTemplate.convertAndSend("hello.yolo", "hello yolo! ni hao!");
    }

4. Broadcast mode

You can refer to: https://blog.csdn.net/fakerswe/article/details/81455340

To put it simply, the message in the exchange (Exchange) is sent to all queues bound to the exchange and ignored routingKey.

Insert picture description here
As can be seen from the figure, after the producer sends the message to the exchange, the exchange sends the message to the consumer queue. If the consumer queue wants to receive the messages in the exchange, it needs to ensure that the name of the exchange bound to the queue must be the same as that of the exchange. This is the key to the broadcast mode and the roughest premise for all subsequent MQ modes.

Here the message is sent to the switch through the producer, and then the switch is sent to the bound queue
(1) Configure the broadcast mode

@Configuration
public class RabbitFanoutConfig {
    
    
    public static final String FANOUTNAME = "yolo-fanout";

    /**
     * 队列1
     * @return
     */
    @Bean
    Queue queueOne() {
    
    
        return new Queue("queue-one");
    }

    /**
     * 队列2
     * @return
     */
    @Bean
    Queue queueTwo() {
    
    
        return new Queue("queue-two");
    }

    /**
     * 交换机
     * @return
     */
    @Bean
    FanoutExchange fanoutExchange() {
    
    
        return new FanoutExchange(FANOUTNAME, true, false);
    }

    /**
     * 绑定队列1
     * @return
     */
    @Bean
    org.springframework.amqp.core.Binding bindingOne() {
    
    
        return BindingBuilder.bind(queueOne()).to(fanoutExchange());
    }

    /**
     * 绑定队列2
     * @return
     */
    @Bean
    Binding bindingTwo() {
    
    
        return BindingBuilder.bind(queueTwo()).to(fanoutExchange());
    }
}

(2) Consumer

/**
 * 定义接收器:消费者
 */
@Component
public class FanoutReceiver {
    
    
    /**
     * 接收消息队列1
     * @param msg
     */
    @RabbitListener(queues = "queue-one")
    public void handler1(String msg) {
    
    
        System.out.println("FanoutReceiver:handler1:" + msg);
    }
    /**
     * 接收消息队列2
     * @param msg
     */
    @RabbitListener(queues = "queue-two")
    public void handler2(String msg) {
    
    
        System.out.println("FanoutReceiver:handler2:" + msg);
    }
}

(3) Test: Producer

  /**
     * 往交换机上发送信息
     */
    @Test
    public void test1() {
    
    
        rabbitTemplate.convertAndSend(RabbitFanoutConfig.FANOUTNAME,null,"hello fanout!");
    }

It should be noted here that you need to start the consumer first, and then start the producer. Otherwise, start the producer first. After the exchange receives the message and finds that there is no queue interested in it, the message will be discarded., Has nothing to do with routingKey at this time

Both queue 1 and queue 2 received the message
Insert picture description here

5. Topic route matching mode

Can refer to: https://blog.csdn.net/weixin_43770545/article/details/90902788

If you want to buy a pair of sports shoes on Taobao, would you search for "XXX sports shoes" in the search box. At this time, the system will fuzzy match all the sports shoes that meet the requirements and show it to you.
The so-called "topic routing matching switch" is also the same reason, but there are certain rules when using it.

String routingkey = “testTopic.#”;
String routingkey = “testTopic.*”;

*Means that only one word
#is matched means that multiple words are matched

(1) Configure topic mode

@Configuration
public class RabbitTopicConfig {
    
    
    public static final String TOPICNAME = "yolo-topic";

    @Bean
    TopicExchange topicExchange() {
    
    
        return new TopicExchange(TOPICNAME, true, false);
    }

    @Bean
    Queue xiaomi() {
    
    
        return new Queue("xiaomi");
    }

    @Bean
    Queue huawei() {
    
    
        return new Queue("huawei");
    }

    @Bean
    Queue phone() {
    
    
        return new Queue("phone");
    }

    @Bean
    Binding xiaomiBinding() {
    
    
        //xiaomi.# 表示如果路由的 routingKey 是以xiaomi 开头就会发送到 xiaomi 这个队列上
        return BindingBuilder.bind(xiaomi()).to(topicExchange()).with("xiaomi.#");
    }

    @Bean
    Binding huaweiBinding() {
    
    
        //huawei.#
        return BindingBuilder.bind(huawei()).to(topicExchange()).with("huawei.#");
    }
    @Bean
    Binding phoneBinding() {
    
    
        // #.phone.# 表示routingKey 中包含 phone 就会被发送到 phone 这个队列上
        return BindingBuilder.bind(phone()).to(topicExchange()).with("#.phone.#");
    }
}

(2) Consumer

@Component
public class TopicReceiver {
    
    
    @RabbitListener(queues = "xiaomi")
    public void handler1(String msg) {
    
    
        System.out.println("TopicReceiver:handler1:" + msg);
    }

    @RabbitListener(queues = "huawei")
    public void handler2(String msg) {
    
    
        System.out.println("TopicReceiver:handler2:" + msg);
    }

    @RabbitListener(queues = "phone")
    public void handler3(String msg) {
    
    
        System.out.println("TopicReceiver:handler3:" + msg);
    }
}

(3) Test: Producer

  @Test
    public void test2() {
    
    
        //可以被小米的队列收到
        rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPICNAME, "xiaomi.news", "小米新闻");
        //可以被手机的队列收到
        rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPICNAME, "vivo.phone", "vivo 手机");
        //可以被华为和手机的队列收到
        rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPICNAME, "huawei.phone", "华为手机");
    }

6. Header mode

This mode uses the key/value (key-value pair) matching queue in the header, and has nothing to do with routingKey

(1) Configure config

@Configuration
public class RabbitHeaderConfig {
    
    
    public static final String HEADERNAME = "yolo-header";

    @Bean
    HeadersExchange headersExchange() {
    
    
        return new HeadersExchange(HEADERNAME, true, false);
    }

    @Bean
    Queue queueName() {
    
    
        return new Queue("name-queue");
    }

    @Bean
    Queue queueAge() {
    
    
        return new Queue("age-queue");
    }

    @Bean
    Binding bindingName() {
    
    
        Map<String, Object> map = new HashMap<>();
        //
        map.put("name", "yolo");
        //whereAny 表示消息的header中只要有一个header匹配上map中的key,value,就把消息发送到对应的队列上
        return BindingBuilder.bind(queueName()).to(headersExchange()).whereAny(map).match();
    }

    @Bean
    Binding bindingAge() {
    
    
        //只要有,age 这个字段,就发送到相应的队列上去
        return BindingBuilder.bind(queueAge()).to(headersExchange()).where("age").exists();
    }
}

(2) Consumer

@Component
public class HeaderReceiver {
    
    
    @RabbitListener(queues = "name-queue")
    public void handler1(byte[] msg) {
    
    
        System.out.println("HeaderReceiver:handler1:" + new String(msg, 0, msg.length));
    }

    @RabbitListener(queues = "age-queue")
    public void handler2(byte[] msg) {
    
    
        System.out.println("HeaderReceiver:handler2:" + new String(msg, 0, msg.length));
    }
}

(3) Test

  @Test
    public void test3() {
    
    
        //对应 RabbitHeaderConfig 中的map 的 key / value
        Message nameMsg = MessageBuilder.withBody("hello yolo !".getBytes()).setHeader("name","yolo").build();
        Message ageMsg = MessageBuilder.withBody("hello 99 !".getBytes()).setHeader("age","99").build();
        //此时发送的消息接收,跟 routingKey无关,跟消息的 header 内容有关
        rabbitTemplate.send(RabbitHeaderConfig.HEADERNAME, null, ageMsg);
        rabbitTemplate.send(RabbitHeaderConfig.HEADERNAME, null, nameMsg);
    }

Insert picture description here
If it is changed, the key-value pair in the header: the match cannot be successful and the queue cannot receive the information

Insert picture description here

Insert picture description here

Guess you like

Origin blog.csdn.net/nanhuaibeian/article/details/108959397