Spring Boot: Spring Boot integrates RabbitMQ

Keywords: RabbitMQ Java Spring SpringBoot

  1. preface
    RabbitMQ is a message queue. When it comes to message queues, you may have heard of it more or less. Its main function is to realize asynchronous and decoupling of application services, as well as to cut peak, fill valley and distribute messages.

One of the main functions of message queuing in comparison is to decouple application services. Messages are delivered from message producers to message queues. Consumers get messages from message queues and consume them. Producers do not need to manage who consumes messages, and consumers do not need to pay attention to who produces messages. In a distributed system, message queuing will also be used in other places, such as the support of distributed transactions, representing RocketMQ, which is an open source of Alibaba. (understand the source code and ask: 1791743380)

Of course, the protagonist of this article is RabbitMQ.

  1. RabbitMQ introduction
    RabbitMQ is a kind of message middleware to realize AMQP (Advanced message queuing protocol). It originated from financial system and used to store and forward messages in distributed system. It has good performance in ease of use, scalability, high availability, etc. RabbitMQ is mainly to realize the bidirectional decoupling between systems. When producers produce a large amount of data, consumers can not consume quickly, so a middle layer is needed. Save this data.

AMQP, Advanced Message Queuing Protocol, is an open standard of application layer protocol, which is designed for message oriented middleware. Message middleware is mainly used to decouple components. The sender of message does not need to know the existence of message consumer, and vice versa. The main characteristics of AMQP are message oriented, queue oriented, routing (including point-to-point and publish / subscribe), reliability and security.

RabbitMQ is an open-source AMQP implementation. The server side is written in Erlang language, and supports a variety of clients, such as Python, Ruby,. NET, Java, JMS, C, PHP, ActionScript, XMPP, STOMP, and AJAX. It is used to store and forward messages in the distributed system, and it has good performance in ease of use, scalability, high availability, etc.

  1. Concept introduction
    In the design of ordinary message queues, there are several concepts: producers, consumers and our queues. But in RabbitMQ, a layer is added in the middle, called Exchange. In this way, the producer does not decide which queue to send the message to, but the message is directly delivered to the switch. The switch decides which queue to send the message to according to the scheduling strategy. As shown in the figure:

The P on the left represents the producer of the message
Purple X stands for switch
Red on the right represents the queue
4. Exchange
So why do we need Exchange instead of sending messages directly to the queue?

The core idea of AMQP protocol is the decoupling between producer and consumer. Producer never sends messages to Queue directly. Producers often don't know if a message will be sent to the Queue, just to a switch. It is received by Exchange, and then Exchange forwards to Queue for storage according to specific policies.

How does Exchange know which queues to send when it receives a message? Here you need to understand the concepts of Binding and RoutingKey:

Binding indicates the relationship between exchange and Queue. We can also simply think that the Queue is interested in messages on the switch. The binding can be accompanied by an additional parameter RoutingKey. Exchange matches the RoutingKey with the binding of all the current exchange bindings. If the matching is met, a message will be sent to the Queue bound by exchange. This solves the problem that we can send a message to RabbitMQ once and distribute it to different queues. The significance of RoutingKey depends on the type of switch.

Let's take a look at the three main types of Exchange: Fanout, Direct, and Topic.

4.1 Direct Exchange

Direct Exchange is RabbitMQ's default Exchange, which routes messages completely according to RoutingKey. When setting the Binding of Exchange and Queue, you need to specify RoutingKey (generally Queue Name), and the same RoutingKey when sending a message, and the message will be routed to the corresponding Queue.

4.2 Topic Exchange

Similar to Direct Exchange, Topic Exchange also needs to route messages through RoutingKey. The difference is that Direct Exchange exactly matches RoutingKey, while Topic Exchange supports fuzzy matching. The * and ා wildcards are supported respectively, * means matching a word, ා means matching no or more words.

4.3 Headers Exchange
Headers Exchange ignores RoutingKey and determines which queues to route based on the headers in the message and the Arguments specified when creating the binding relationship.

The performance of Headers Exchange is poor, and Direct Exchange can completely replace it, so it is not recommended.

4.4 Default Exchange
Default Exchange is a special kind of Direct Exchange. When you manually create a queue, the background will automatically bind the queue to a Direct Exchange with an empty name. The binding RoutingKey is the same as the queue name. With this default switch and binding, we only care about the queue layer, which is more suitable for some simple applications.

  1. Spring Boot integrates RabbitMQ
    Spring Boot is very simple to integrate RabbitMQ. If it is only a simple configuration, Spring Boot provides a variety of support for messages in the Spring Boot starter AMQP project.

5.1 simple use
Introduce dependency

Code listing: spring boot rabbitmq/ pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

Profile application.yml As follows:

Code listing: spring boot rabbitmq / SRC / main / resources/ application.yml

server:
  port: 8080
spring:
  application:
    name: spring-boot-rabbitmq
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: admin

Queue configuration

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / config/ QueueConfig.java

@Configuration
public class QueueConfig {
    @Bean
    public Queue simpleQueue() {
        return new Queue("simple");
    }

    @Bean
    public Queue simpleOneToMany() {
        return new Queue("simpleOneToMany");
    }
}

Message provider

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / simple/ SimpleSend.java

@Component
public class SimpleSend {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AmqpTemplate amqpTemplate;

    public void send() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String message = "Hello Spring Boot " + simpleDateFormat.format(new Date());
        amqpTemplate.convertAndSend("simple", message);
        logger.info("Message push succeeded!");
    }
}

Message consumer

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / simple/ SimpleReceive.java

@Component
@RabbitListener(queues = "simple")
public class SimpleReceive {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @RabbitHandler
    public void process(String message) {
        logger.info("Receive :{}", message);
    }

}

test

Code listing: spring boot rabbitmq / SRC / test / Java / COM / springboot / springbootrabbitmq/ DemoApplicationTests.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    SimpleSend simpleSend;

    @Test
    public void simpleSend() {
        simpleSend.send();
    }

}

5.2 one to many use
What happens if there is a producer of one message and a consumer of N messages?

Make some changes to the above code to add a message consumer.

The test code is as follows:

@Test
public void simpleOneSend() {
    for (int i = 0; i < 100; i ++) {
        simpleManySend.send(i);
    }
}

The test shows that two consumers consume the producer's message on average.

5.3 many to many use
We add a message producer, and the test code is as follows:

@Test
public void simpleManySend() {
    for (int i = 0; i < 100; i ++) {
        simpleManySend.send(i);
        simpleManySend1.send(i);
    }
}

The test results show that two consumers consume the messages produced by two producers on average.

5.4 Topic Exchange
First, configure the Topic. The configuration code is as follows:

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / config/ TopicConfig.java

@Configuration
public class TopicConfig {

    private final String message = "topic.message";
    private final String messages = "topic.messages";

    @Bean
    public Queue queueMessage() {
        return new Queue(this.message);
    }

    @Bean
    public Queue queueMessages() {
        return new Queue(this.messages);
    }

    @Bean
    TopicExchange exchange() {
        return new TopicExchange("topicExchange");
    }

    @Bean
    Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }

    @Bean
    Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
    }
}

Here queue messages can match two routes at the same time_ Key, while queue queueMessage can only match topic.message .

The producer code of the message is as follows:

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / topic/ TopicSend.java

@Component
public class TopicSend {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send1() {
        String message = "message 1";
        logger.info("send:{}", message);
        rabbitTemplate.convertAndSend("topicExchange", "topic.message", message);
    }

    public void send2() {
        String message = "message 2";
        logger.info("send:{}", message);
        rabbitTemplate.convertAndSend("topicExchange", "topic.messages", message);
    }
}

The call to send1() is forwarded to both queues by Exchange, while the call to send2() is only forwarded to receive2.

5.5 Fanout Exchange
Fanout is a familiar broadcast mode or subscription mode. It sends messages to fanout switch, and all queues bound to the switch receive the messages.

Fanout is configured as follows:

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / config/ FanoutConfig.java

@Configuration
public class FanoutConfig {
    @Bean
    public Queue MessageA() {
        return new Queue("fanout.A");
    }

    @Bean
    public Queue MessageB() {
        return new Queue("fanout.B");
    }

    @Bean
    public Queue MessageC() {
        return new Queue("fanout.C");
    }

    @Bean
    FanoutExchange fanoutExchange() {
        return new FanoutExchange("fanoutExchange");
    }

    @Bean
    Binding bindingExchangeA(Queue MessageA, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(MessageA).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeB(Queue MessageB, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(MessageB).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeC(Queue MessageC, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(MessageC).to(fanoutExchange);
    }
}

The message producer code is as follows:

Code listing: spring boot rabbitmq / SRC / main / Java / COM / springboot / springbootrabbitmq / fanout/ FanoutSend.java

@Component
public class FanoutSend {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        String message = "Hello FanoutSend.";
        logger.info("send:{}", message);
        this.rabbitTemplate.convertAndSend("fanoutExchange","", message);
    }
}

The test code is as follows:

Code listing: spring boot rabbitmq / SRC / test / Java / COM / springboot / springbootrabbitmq/ DemoApplicationTests.java

@Test
public void fanoutSend() {
    fanoutSend.send();
}

The test result is that the queues bound to the fanout switch have received messages.

Posted by .Stealth on Wed, 17 Jun 2020 19:10:40 -0700