One of the RabbitMQ guides: "Hello World!"

  Why use MQ message middleware? What problem does it solve? About why use message middleware? How does the message middleware achieve synchronization to asynchronous, traffic cutting, and application decoupling? There are many explanations on the Internet, so I won't explain them here. In the next RabbitMq series of blogs, I will translate the official explanation and organize it into a blog with my own understanding. I hope to communicate with you and make progress together.

                  RabbitMq schematic

1. Introduction to RabbitMq

  RabbitMq is a message middleware: it receives messages and forwards them. You can think of it as a post office: when you put a letter in the mailbox, the postmen can finally deliver the letter to the recipient. Similarly, RabbitMq is like a mailbox, post office and postman. The biggest difference between RabbitMq and the post office is that RabbitMq receives and forwards binary data blocks - messages, not paper data files.

  RabbitMq, message related terms are as follows:

  Producer : The producer only sends messages, and the program that sends the message is the producer:

  Message queue : The message queue is equivalent to the mailbox name in RabbitMq. Although the message flows in your program and RabbitMq, it can only be stored in the message queue. A queue is essentially a large message buffer, and how many messages it can hold depends on the memory and disk constraints of the host. Multiple producers can send messages to the same message queue; multiple consumers can get data from the same queue. We represent a message queue with the following graph:

  Consumer : A consumer is a program that waits to receive messages:

  Note: The producer, consumer and RabbitMq can be on different machines; in many applications, a producer may also be a consumer.

2、“Hello World!”

   In this section, we will write a message producer to send messages and a message consumer to consume messages (receive messages and print them).

  In the graphic below, "P" is our producer, "C" is our consumer, and the red box in the middle is our message queue, which holds messages received from producers that are ready to be forwarded to consumers.

Java client class library description:

  RabbitMq uses a variety of protocols, this guide uses the AMQP 0-9-1 protocol, which is an open-source, general-purpose messaging protocol. RabbitMq has clients in multiple languages, here we use the client in JAVA language for experiments. Download the RabbitMq client jar package and dependency packages from the following address:

  amqp-client-5.5.1.jar

  slf4j-api-1.7.25.jar

  slf4j-simple-1.7.25.jar

  Copy these three jar packages to your working directory, including the new java files to be created in the following tutorials.

2.1 Sending a message

  The producer connects to RabbitMq, sends a simple message "Hello World!" and exits.

  In the Send.java class, the following dependencies need to be introduced:

1 import com.rabbitmq.client.ConnectionFactory;
2 import com.rabbitmq.client.Connection;
3 import com.rabbitmq.client.Channel;

  Give the queue a name:

1 public class Send {
2   private final static String QUEUE_NAME = "hello";
3   public static void main(String[] argv) throws Exception {
4       ...
5   }
6 }

  Create a collection of connections to the server:

1 onnectionFactory factory = new ConnectionFactory();
2 factory.setHost("localhost");
3 try (Connection connection = factory.newConnection();
4      Channel channel = connection.createChannel()) {
5 
6 }

  This connection, the socket connection, handles protocol version negotiation, authentication, etc. for us. Here we connect to a local RabbitMq: hence localhost, if you want to connect to RabbitMq on a remote machine, just change localhst to the computer name or IP address of that machine.

  After creating the connection, we continue to create a channel: Channel. We need to use the try-with-resource expression, because both Connection and Channel implement the JAVA interface Closeable, which are resources and need to be closed, so we don't need to explicitly close them in our code. (For the channel, please refer to the RabbitMq schematic at the top of the article, which is a virtual link in TCP. For example, a cable is equivalent to a TCP, and a channel is an independent fiber inside. It is no problem to create multiple channels on a TCP; TCP Once opened, the AMQP channel is created; whether publishing messages, receiving messages, subscribing to queues, these actions are all done through the channel).

  In order to send a message, we must also define a message queue to send to, using the try-with-resource expression:

1 channel.queueDeclare(QUEUE_NAME, false, false, false, null);
2 String message = "Hello World!";
3 channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
4 System.out.println(" [x] Sent '" + message + "'");

  Defining a message queue is idempotent: it can only be created if the queue does not exist, and messages are binary arrays, so you can specify the encoding as needed.

  The completed Send.java is as follows:

 1 import com.rabbitmq.client.Channel;
 2 import com.rabbitmq.client.Connection;
 3 import com.rabbitmq.client.ConnectionFactory;
 4 
 5 public class Send {
 6 
 7     private final static String QUEUE_NAME = "hello";
 8 
 9     public static void main(String[] argv) throws Exception {
10         ConnectionFactory factory = new ConnectionFactory();
11         factory.setHost("localhost");
12         try (Connection connection = factory.newConnection();
13              Channel channel = connection.createChannel()) {
14             channel.queueDeclare(QUEUE_NAME, false, false, false, null);
15             String message = "Hello World!";
16             channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
17             System.out.println(" [x] Sent '" + message + "'");
18         }
19     }
20 }

2.2 Receive messages

  The consumer listens for messages in RabbitMq, so instead of the producer sending a message and then exiting, the consumer keeps running to receive messages and print them.

  Recv.java also needs to import the following dependencies:

1 import com.rabbitmq.client.Channel;
2 import com.rabbitmq.client.Connection;
3 import com.rabbitmq.client.ConnectionFactory;
4 import com.rabbitmq.client.DeliverCallback;

  Same as the producer, we need to create the Connetcion and Channel, define the queue (the queue that needs to listen and receive messages):

 1 public class Recv {
 2 
 3   private final static String QUEUE_NAME = "hello";
 4 
 5   public static void main(String[] argv) throws Exception {
 6     ConnectionFactory factory = new ConnectionFactory();
 7     factory.setHost("localhost");
 8     Connection connection = factory.newConnection();
 9     Channel channel = connection.createChannel();
10 
11     channel.queueDeclare(QUEUE_NAME, false, false, false, null);
12     System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
13 
14   }
15 }

  Note that we are also declaring the queue here, because we may start the consumer before the producer, and we want to make sure the queue is there when we try to consume the message.

  Here why don't we use try-with-resource expressions to automatically close channl and connection? By doing this, we can keep our program running all the time, and if these are turned off, the program will stop. This is embarrassing, because we need to keep the consumer in a state of asynchronously listening for messages.

  RabbitMq will push the messages in the queue asynchronously, we need to provide a callback function to buffer the messages until we need them:

1 DeliverCallback deliverCallback = (consumerTag, delivery) -> {
2     String message = new String(delivery.getBody(), "UTF-8");
3     System.out.println(" [x] Received '" + message + "'");
4 };
5 channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });

  Rec.java complete code:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;

public class Recv {

    private final static String QUEUE_NAME = "hello";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
    }
}

3. Test

  In the official manual, in the test part, they add the client jar and the dependent jar to the classpath path, and then run it in the cmd terminal. I find it troublesome. Therefore, I put it in IDEA to run it, and the effect is the same.

  Step 1: First run Send.java:

  Output result:

[x] Sent 'Hello World!'

  Check out the RabbitMq console:

  Indicates that the message has been sent successfully.

    Step 2: Start the consumer Recv.java:

  Output result:

[x] Received 'Hello World!'

  It means that the message has been successfully consumed, and then check the console again:

  The message still exists in the queue, but the difference is that in the first picture, Ready changed from 1 to 0, and Unacknowledged changed from 0 to 1; in the second picture, Ready also changed from 1 to 0, and Unacked changed from 0 to 1. Why is this happening? Logically, the message should be deleted after it is consumed, otherwise it may cause repeated consumption. This knowledge will be introduced in later chapters (Ack mechanism).

4. Implemented with SpringBoot

  Although the above functions are implemented, in actual work, we are more likely to use mature frameworks such as Spring Boot and Spring Cloud to implement them. This section implements the above functions through SpringBoot.

  Select RabbitMq when creating the project:

  The project directory is as follows:

  The configuration files of Provider and Consumer are the same, please replace the IP with your own:

1 #RabbitMq
2 spring.rabbitmq.host=192.168.xx.xx  
3 spring.rabbitmq.username=rabbitmq
4 spring.rabbitmq.password=123456
5 
6 hello_world.queue=hello

  In order to facilitate sending messages to the queue when the system starts, a SenderRunner class is written:

 1 @Component
 2 public class SenderRunner implements ApplicationRunner {
 3 
 4     @Autowired
 5     private Send send;
 6 
 7     @Override
 8     public void run(ApplicationArguments args) throws Exception {
 9         send.doSender("Hello RabbitMq");
10     }
11 }

  Send.java

 1 @Component
 2 public class Send {
 3 
 4     @Value("${hello_world.queue}")
 5     private String queueName;
 6 
 7     @Autowired
 8     private AmqpTemplate amqpTemplate;
 9 
10     public void doSender(String msg) {
11 
12         amqpTemplate.convertAndSend(queueName,msg);
13         System.out.println("发送消息:" + msg);
14     }
15 }

  Startup class:

1 @SpringBootApplication
2 public class ProviderApplication {
3     public static void main(String[] args) {
4         SpringApplication.run(ProviderApplication.class, args);
5     }
6 }

  Recv.java

@Component
public class Recv {

    @RabbitListener(queues = "${hello_world.queue}")
    public void receive(String msg) {
        System.out.println("接收到消息:" + msg);
    }
}

  Start the provider:

  View the console:

  Start Consumer:

  It can be seen that SpringBoot has done a lot of encapsulation for us, hiding many underlying details, and it is much simpler to use.

Pay attention, don't get lost, this is a QR code that programmers want to pay attention to

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324064468&siteId=291194637