In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article is about how to use SpringBoot+RabbitMQ to send and receive messages. The editor thinks it is very practical, so I share it with you. I hope you can get something after reading this article. Let's take a look at it.
This article will be integrated with SpringBoot and developed in the way of automatic configuration. We only need to declare the RabbitMQ address. Spring will help us with all kinds of things about creating connections and closing connections.
Handing over connections to Spring allows us to focus on business logic, which is as easy to use, convenient and efficient as declarative transactions.
I wish you a good harvest, like it first and then see it, and be happy.
1.? Environment configuration
In the first section, let's take a look at the configuration of the environment. In the previous article, we have introduced the automatic configuration package. Since we have used the automatic configuration method, we can directly put the connection information of RabbitMQ in the configuration file, just as we need to configure DataSource when we need to use JDBC connection.
As shown in the figure, we only need to specify the IP+ port number and username password of the connection. Here I use the default username and password. If you don't write it, the default is guest, and the port number is 5672 by default.
Mainly, we need to take a look at the manual confirmation message configuration, which needs to be configured as manual to manually confirm. There will be other configuration items in the future. We can configure this one now.
Next we need to configure a Queue. In the previous article, we sent messages to a queue called erduo, which we defined manually at that time. Here we also need to manually configure and declare a Bean.
@ Configuration public class RabbitmqConfig {@ Bean public Queue erduo () {/ / its three parameters: durable exclusive autoDelete / / generally only set persistence to return new Queue ("erduo", true);}}
Just make a simple declaration, of course, RabbitMQ is an independent component after all, if you have created a queue called erduo in RabbitMQ in other ways, you can not declare it here, one of the effects here is that if you do not have the queue, it will help you create the queue in the way you declared.
Once the environment is configured, we can write producers and consumers in a SpringBoot way.
2.? Producer and RabbitTemplate
At the same pace as the previous article, let's write producers first, but this time I'm going to introduce a new tool: RabbitTemplate.
Listen to its name, it is another ready-to-use tool class, the Spring family is very comfortable, everything is encapsulated for you to make it more convenient and convenient for you to use.
RabbitTemplate implements the standard AmqpTemplate interface, which can be roughly divided into sending messages and receiving messages.
We use it here in the producer, mainly using its messaging function: send and convertAndSend methods.
/ / send a message to the default Exchange, use the default routing key void send (Message message) throws AmqpException; / / send a message to the default exchange void send (String routingKey, Message message) throws AmqpException; / / send a message to the specified exchange void send (String exchange, String routingKey, Message message) throws AmqpException using the specified routing key.
The send method is the mode that sends the data of the byte array. Here, the object that represents the content of the message is the Message object, and its construction method is to pass in the byte array data, so we need to convert our data into a byte array and then construct a Message object to send.
/ / Object type. You can input POJO void convertAndSend (Object message) throws AmqpException; void convertAndSend (String routingKey, Object message) throws AmqpException; void convertAndSend (String exchange, String routingKey, Object message) throws AmqpException
The convertAndSend method can pass in a POJO object as a parameter, and at the bottom there is a MessageConverter that helps us automatically convert the data to a byte type or a String or serialization type.
So there are only three types of incoming objects supported here: byte type, String type, and POJO that implements the Serializable interface.
After the introduction, we can take a look at the code:
@ Slf4j @ Component ("rabbitProduce") public class RabbitProduce {@ Autowired private RabbitTemplate rabbitTemplate; public void send () {String message = "Hello I am the author and ear, welcome to follow me." + LocalDateTime.now () .toString (); System.out.println ("Message content:" + message); / / specify message type MessageProperties props = MessagePropertiesBuilder.newInstance () .setContentType (MessageProperties.CONTENT_TYPE_TEXT_PLAIN) .build (); rabbitTemplate.send (Producer.QUEUE_NAME,new Message (message.getBytes (StandardCharsets.UTF_8), props)) System.out.println ("message has been sent.") ;} public void convertAndSend () {User user = new User (); System.out.println ("Message content:" + user); rabbitTemplate.convertAndSend (Producer.QUEUE_NAME,user); System.out.println ("message sent complete.") ;}}
Here I specifically specify two examples, one to test send and the other to test convertAndSend.
In the send method, we look almost the same as the previous code, define a message, and then directly send, but the construction method of this construction message may have one more parameter than we thought. We just said that we just need to convert the data into a binary array and put it into it. Now it seems that we need to put one more parameter.
MessageProperties, yes, we need to put an extra MessageProperties object, from his name we can also see that its function is to attach some parameters, but some parameters are indispensable.
For example, my code here sets the type of message. There are many types of message that can be binary type, text type, or serialization type, or JSON type. What I set here is the text type, which specifies that the type is required. It can also provide a reference for what kind of object we want to convert the message into after we get the message.
The convertAndSend method is much simpler. Here I put a User object for testing, specify the queue directly and put it into this object.
Tips:User must implement the Serializable interface, otherwise an IllegalArgumentException exception will be thrown when this method is called.
After the code is complete, we can call. Here I write a test class to make the call:
@ SpringBootTest public class RabbitProduceTest {@ Autowired private RabbitProduce rabbitProduce; @ Test public void sendSimpleMessage () {rabbitProduce.send (); rabbitProduce.convertAndSend ();}}
The effect is as follows ~
At the same time, use the command rabbitmqctl.bat list_queues in the console to view the current situation of queue-erduo:
In this way, our producer test is complete, and now there are two messages in the message queue, and the message type must be different, one is the text type we set, and the other is the serialization type that is automatically set.
3.? Consumers and RabbitListener
Now that there is a message in the queue, let's see how we can get the message and consume and confirm it in a new way.
For consumers, we need to use @ RabbitListener to help us get the specified queue message. Its usage is very simple and complicated. We can first talk about the simple way, put it directly to the method, and specify the queue to listen on.
@ Slf4j @ Component ("rabbitConsumer") public class RabbitConsumer {@ RabbitListener (queues = Producer.QUEUE_NAME) public void onMessage (Message message, Channel channel) throws Exception {System.out.println ("Message content:" + message); channel.basicAck (message.getMessageProperties (). GetDeliveryTag (), false); System.out.println ("message confirmed");}}
This code means that the onMessage method processes messages in the erduo (Producer.QUEUE_NAME is the constant string "erduo") queue.
We can see that there are two parameters in this method, Message and Channel. You don't have to write this parameter if you don't need Channel, but the Message message must be required, which represents the message itself.
We can think about how our program is going to show us after pulling back messages from RabbitMQ.
Yes, it is encapsulated into Message objects, which contains all the information of a message. You can see what the data structure is like as soon as I run.
At the same time, we use Channel to do a message confirmation operation, where DeliveryTag represents the sequence number of the message in the queue, and this information is stored in MessageProperties.
4.? SpringBoot start!
After writing the producer and the consumer, and having run the producer and put two messages into the message queue, we can start the message directly to check the consumption:
As you can see in my red box mark, because we have consumers, we first establish a connection with RabbitMQ to listen in queue after the project is started.
Then we start consuming two messages in our queue:
The first message is of type contentType=text/plain, so the details are printed directly on the console.
The second message is contentType=application/x-java-serialized-object, which prints only one memory address + byte size.
In any case, we got the data, which means that there is no problem with our consumption. At the same time, we also carried out the message confirmation operation. From the data point of view, the whole message can be divided into two parts: body and MessageProperties.
We can use a single annotation to get the content of this body-@ Payload
@ RabbitListener (queues = Producer.QUEUE_NAME) public void onMessage (@ Payload String body, Channel channel) throws Exception {System.out.println ("Message content:" + body);}
You can also use a single annotation to get the headers attribute of MessageProperties. The headers attribute can also be seen in the screenshot, but it is empty-@ Headers.
@ RabbitListener (queues = Producer.QUEUE_NAME) public void onMessage (@ Payload String body, @ Headers Map headers) throws Exception {System.out.println ("Message content:" + body); System.out.println ("Message headers:" + headers);}
Both of these notes can be regarded as extended knowledge, but I prefer to get all of them directly, all of them!
We have finished sending and consuming the message above, and we can recall again that everything follows the same trajectory as in the picture I drew:
It's just that we haven't specified the default route that Exchage has been using all the time. I hope you will remember this picture well.
5. @ RabbitListener and @ RabbitHandler
Let's add some more knowledge points about @ RabbitListener and @ RabbitHandler.
We have simply used @ RabbitListener above. With a little extension, it can actually listen to multiple queues, like this:
@ RabbitListener (queues = {"queue1", "queue2"}) public void onMessage (Message message, Channel channel) throws Exception {System.out.println ("Message content:" + message); channel.basicAck (message.getMessageProperties (). GetDeliveryTag (), false) System.out.println ("message confirmed");}
There are other features such as bindings, which I won't repeat here because they are too hard-coded to be used.
Let's talk about one of the main features of this section: the combination of @ RabbitListener and @ RabbitHandler.
As we didn't mention earlier, the @ RabbitListener annotation can actually be annotated on a class, which indicates that the class listens on a queue or queues.
The matching use of these two annotations is to have @ RabbitListener annotated on the class, and then use @ RabbitHandler annotation on the method to automatically identify and consume according to the different method parameters. It is more intuitive to write an example to show you.
@ Slf4j @ Component ("rabbitConsumer") @ RabbitListener (queues = Producer.QUEUE_NAME) public class RabbitConsumer {@ RabbitHandler public void onMessage (@ Payload String message) {System.out.println ("Message content:" + message);} @ RabbitHandler public void onMessage (@ Payload User user) {System.out.println ("Message content:"+ user);}}
You can take a look at this example. We first listen for messages in the erduo queue with @ RabbitListener, and then annotate two methods with @ RabbitHandler.
The body type of the first method is String, which means that this method can only handle messages of text type.
The body type of the second method is the User type, which means that this method can only handle messages of serialized type and of type User.
These two methods correspond to the two messages that our test class will send in the second section, so we send two test messages to RabbitMQ to test this code to see the effect:
All are printed on the console as usual. If none of the @ RabbitHandler annotation methods can match the type of your message, for example, messages are all byte array types, and there is no corresponding method to receive them, the system will continue to report errors on the console. If this happens, it will prove that your type is incorrect.
Suppose there are three types of messages in your erduo queue: byte, text and serialization, then you must have a corresponding method to deal with these three messages, otherwise the message will be sent with an error because it cannot be converted correctly.
And after using the @ RabbitHandler annotation, you can no longer use Message as the receive type as before.
@ RabbitHandler public void onMessage (Message message, Channel channel) throws Exception {System.out.println ("Message content:" + message); channel.basicAck (message.getMessageProperties (). GetDeliveryTag (), false); System.out.println ("message confirmed");}
If you write like this, you will report an exception in type conversion, so choose one or the other.
At the same time, my @ RabbitHandler above did not confirm the message, so you can try it yourself.
6.? Serialization transformation of messages
As we already know above, the only objects that can be automatically converted are byte [], String, and java serialization objects (objects that implement the Serializable interface), but not all Java objects implement the Serializable interface, and the serialization method inherent in JDK is used in the serialization process, which is inefficient.
So our more common practice is to use Jackson to convert the data into JSON format and send it to RabbitMQ, and then use Jackson to deserialize the data when receiving the message.
This perfectly addresses the pain point above: message objects no longer have to implement the Serializable interface and are more efficient (Jackson serialization efficiency should be the best in the industry).
The default message transformation scheme is a subclass of the message transformation top-level interface-MessageConverter: SimpleMessageConverter, which we just need to replace if we want to switch to another message converter.
The image above is the structure tree of the MessageConverter structure tree. You can see that there is a Jackson2JsonMessageConverter in addition to SimpleMessageConverter. We only need to define it as Bean to use this converter directly.
@ Bean public MessageConverter jackson2JsonMessageConverter () {return new Jackson2JsonMessageConverter (jacksonObjectMapper);}
This is fine, jacksonObjectMapper can not be passed in here, but the default ObjectMapper scheme for JDK8 time and date serialization will not be very friendly, you can refer to my previous article: from LocalDateTime serialization to explore global consistent serialization, generally speaking, is to define your own ObjectMapper.
At the same time, for the convenience of the next test, I defined a queue specifically for testing JSON serialization:
@ Bean public Queue erduoJson () {/ / its three parameters: durable exclusive autoDelete / / generally only set persistence to return new Queue ("erduo_json", true);}
After that, you can test, first with the producer code:
Public void sendObject () {Client client = new Client (); System.out.println ("Message content:" + client); rabbitTemplate.convertAndSend (RabbitJsonConsumer.JSON_QUEUE,client); System.out.println ("message sent complete.") ;}
I redefined a Client object, which is the same as the User object member variables used in the previous test, except that it does not implement the Serializable interface.
At the same time, in order to retain the previous test code, I created a new RabbitJsonConsumer to test the consumer code related to JSON serialization, which defines a static variable: JSON_QUEUE = "erduo_json"
So this code sends the Client object as a message to the "erduo_json" queue, and then we run it once in the test class.
Next to it is the consumer code:
@ Slf4j @ Component ("rabbitJsonConsumer") @ RabbitListener (queues = RabbitJsonConsumer.JSON_QUEUE) public class RabbitJsonConsumer {public static final String JSON_QUEUE = "erduo_json"; @ RabbitHandler public void onMessage (Client client, @ Headers Map headers, Channel channel) throws Exception {System.out.println ("Message content:" + client); System.out.println ("Message headers:" + headers) Channel.basicAck ((Long) headers.get (AmqpHeaders.DELIVERY_TAG), false); System.out.println ("message confirmed");}}
With the experience above, this code is easy to understand, and shows how to sign messages in @ RabbitHandler mode that was not written in the previous section.
Let's take a look at the effect directly:
In the printed Headers, you can see contentType=application/json. This contentType indicates the type of message, which means that our new message converter has taken effect, converting all messages to JSON type.
Postscript
These two articles have finished talking about the basic sending and receiving messages of RabbitMQ, including manual configuration and automatic configuration. After studying these carefully, you should have no doubt about RabbitMQ sending and receiving messages.
However, we always use the default switch when we send messages. The next section will talk about several switch types of RabbitMQ and how they are used.
The above is how to send and receive messages by SpringBoot+RabbitMQ. The editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.