1, Introduction
message middleware has a series of functions, such as low coupling, reliable delivery, broadcasting, flow control, final consistency, etc. it has become one of the main means of asynchronous RPC, such as ActiveMQ, RabbitMQ, Kafka, RocketMQ, etc. The main functions of message oriented middleware are as follows:
- Asynchronous processing
- Application decoupling
- Flow peak clipping
- Log processing
RabbitMQ's default container is the simple container. Since version 2.0, there has been a direct container. Let's see the difference from the perspective of distributed architecture. This article mainly uses Spring Boot (2.5.2) to integrate RabbitMQ (2.5.2) and simple container to implement a consumer. The premise of this article is to have an installed RabbitMQ environment.
1.1 notes in this document
- @Configuration: used to define the configuration class. The annotated class can contain one or more methods annotated by @ bean. These methods will be scanned by AnnotationConfigApplicationContext or AnnotationConfigWebApplicationContext classes, and used to build bean definitions and initialize the Spring container
- @RabbitListener: @ RabbitListener annotation specifies the target method as the method of consuming messages, and specifies the listening queue or Binding through the annotation parameter@ The RabbitListener tag on the class indicates that when a message is received, it will be handed over to the method of @ RabbitHandler for processing
- @RabbitHandler: it should be used together with the @ RabbitListener annotation. When a message is received, relevant methods will be called according to the parameter type converted by the MessageConverter
2, Maven dependency
pom.xml
<?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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.2</version> <relativePath/> </parent> <groupId>com.alian</groupId> <artifactId>rabbitmq-simple</artifactId> <version>0.0.1-SNAPSHOT</version> <name>rabbitmq-simple</name> <description>SpringBoot integration RabbitMQ of simple Container (consumer)</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${parent.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${parent.version}</version> </dependency> <!--rabbitMq The best version and springboot bring into correspondence with--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <version>${parent.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.68</version> </dependency> <!--For serialization--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.10</version> </dependency> <!--java 8 Time serialization--> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.10</version> </dependency> <!--It is packaged and uploaded to the private server for testing--> <dependency> <groupId>com.alian</groupId> <artifactId>common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
it should be noted here that the following package is packaged into the private server by myself. In fact, an employee class, a payment class, and a constant class. You can also package your own entities into the private server, or directly implement my example through module development.
<dependency> <groupId>com.alian</groupId> <artifactId>common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
3, Configuration class
3.1 basic configuration
at the beginning of this article, we will complete this integration from the perspective of distributed architecture. We will use two system consumers and producers to complete this test. This troublesome way is not to avoid unit testing or module development, but to avoid everyone stepping on the pit, which is closer to our actual development. Therefore, I prepared several simple classes (MQConstants.java, Employee.java and PayRecord.java) in advance and put them into a jar package to maven private server. A configuration class stores MQ constants, an employee class and a payment class. The properties inside are common types, as follows.
MQConstants .java
package com.alian.common.constant; public class MQConstants { /** * Switch */ public final static String ALIAN_EXCHANGE_NAME = "ALIAN_EXCHANGE"; /** * Queue name */ public final static String ALIAN_QUEUE_NAME = "ALIAN_QUEUE"; /** * Routing key */ public final static String ALIAN_ROUTINGKEY_NAME = "ALIAN_ROUTINGKEY"; }
Employee.java
package com.alian.common.dto; import java.io.Serializable; import java.time.LocalDate; import java.util.Objects; public class Employee implements Serializable { private static final long serialVersionUID = 1L; /** * Employee number */ private String id = ""; /** * Employee name */ private String name = ""; /** * Employee age */ private int age; /** * wages */ private double salary = 0.00; /** * department */ private String department = ""; /** * Entry time */ private LocalDate hireDate = LocalDate.of(1970, 1, 1); /** * Note: the serialized object should provide a parameterless constructor, otherwise an exception will be thrown */ public Employee() { } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } public LocalDate getHireDate() { return hireDate; } public void setHireDate(LocalDate hireDate) { this.hireDate = hireDate; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + ", department='" + department + '\'' + ", hireDate=" + hireDate + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Employee)) return false; Employee employee = (Employee) o; return getAge() == employee.getAge() && Double.compare(employee.getSalary(), getSalary()) == 0 && Objects.equals(getId(), employee.getId()) && Objects.equals(getName(), employee.getName()) && Objects.equals(getDepartment(), employee.getDepartment()) && Objects.equals(getHireDate(), employee.getHireDate()); } @Override public int hashCode() { return Objects.hash(getId(), getName(), getAge(), getSalary(), getDepartment(), getHireDate()); } }
PayRecord.java
package com.alian.common.dto; import java.io.Serializable; import java.time.LocalDateTime; import java.util.Objects; public class PayRecord implements Serializable { private static final long serialVersionUID = 1L; /** * Payment flow */ private String payTranSeq = ""; /** * Payment amount (unit: minute) */ private int payAmount; /** * Payment method (00: cash, 01: WeChat, 02: Alipay, 03: UnionPay, 04: other) */ private String payType = "01"; /** * Payment status (00: payment succeeded, 01: to be paid, 02: payment failed, 03: cancelled) */ private String status = "01"; /** * Payment time */ private LocalDateTime payTime = LocalDateTime.now(); /** * Third party flow */ private String payNo = ""; /** * Note: the serialized object should provide a parameterless constructor, otherwise an exception will be thrown */ public PayRecord() { } public String getPayTranSeq() { return payTranSeq; } public void setPayTranSeq(String payTranSeq) { this.payTranSeq = payTranSeq; } public int getPayAmount() { return payAmount; } public void setPayAmount(int payAmount) { this.payAmount = payAmount; } public String getPayType() { return payType; } public void setPayType(String payType) { this.payType = payType; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public LocalDateTime getPayTime() { return payTime; } public void setPayTime(LocalDateTime payTime) { this.payTime = payTime; } public String getPayNo() { return payNo; } public void setPayNo(String payNo) { this.payNo = payNo; } @Override public String toString() { return "PayRecord{" + "payTranSeq='" + payTranSeq + '\'' + ", payAmount=" + payAmount + ", payType='" + payType + '\'' + ", status='" + status + '\'' + ", payTime=" + payTime + ", payNo='" + payNo + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PayRecord)) return false; PayRecord payRecord = (PayRecord) o; return getPayAmount() == payRecord.getPayAmount() && Objects.equals(getPayTranSeq(), payRecord.getPayTranSeq()) && Objects.equals(getPayType(), payRecord.getPayType()) && Objects.equals(getStatus(), payRecord.getStatus()) && Objects.equals(getPayTime(), payRecord.getPayTime()) && Objects.equals(getPayNo(), payRecord.getPayNo()); } @Override public int hashCode() { return Objects.hash(getPayTranSeq(), getPayAmount(), getPayType(), getStatus(), getPayTime(), getPayNo()); } }
3.2 switch, route and queue configuration
specific explanation, I believe the code makes it very clear. com.alian.common.constant.MQConstants is in my public package. The specific code is in mqconstants java
ExchangeConfig.java
package com.alian.rabbitmq.config; import com.alian.common.constant.MQConstants; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ExchangeConfig { /** * Define switch * * @return */ @Bean public DirectExchange defaultExchange() { return new DirectExchange(MQConstants.ALIAN_EXCHANGE_NAME); } /** * Define a queue (persistence) * * @return */ @Bean public Queue aLianQueue() { return new Queue(MQConstants.ALIAN_QUEUE_NAME, true); } /** * Bind queue, and send messages to the specified queue through the specified switch and routing key (a queue can bind multiple routing keys) * * @return */ @Bean public Binding aLianBinding() { return BindingBuilder.bind(aLianQueue()).to(defaultExchange()).with(MQConstants.ALIAN_ROUTINGKEY_NAME); } }
As for the configuration of switches, routes and queues, I have a few suggestions that you can refer to (they have been miserable by those who don't pay attention to these, and an MQ has made a mess).
- It is better to define the switch, route and queue through the program rather than manual operation on the console. The console is mainly used to check the relationship between the three, or to view the operation of connection and queue messages
- For the naming of switches, it is recommended that one switch be used for one platform, for example, 10 systems on one platform share one switch
- For the naming of the route, it is best to associate it with the system to let everyone know which system the route goes to
- For the naming of queues, it is best to know which system or function is used, and to realize queue persistence, that is, when defining queues, durable is true
- The names of switches, routes and queues are put into a public jar, so that all systems can be easily consulted, named and managed in a unified manner, so as to avoid mq abuse, duplication and relationship confusion
I suppose I have a payment platform here, which has query system, notification system, business request system, refund system, etc. both query system and notification system use dead letter queue for corresponding query or notification functions. The approximate name is as follows:
Queue type | Switch | route | queue |
---|---|---|---|
Notification system general queue | PT_EXCHANGE | NTS_ROUTINGKEY | NTS_QUEUE |
Query system general queue | PT_EXCHANGE | OIS_ROUTINGKEY | OIS_QUEUE |
Notification system dead letter queue | PT_DELAY_EXCHANGE | NTS_DELAY_ROUTINGKEY | NTS_DELAY_QUEUE |
Query system dead letter queue | PT_DELAY_EXCHANGE | OIS_DELAY_ROUTINGKEY | OIS_DELAY_QUEUE |
3.3 RabbitMq configuration (Jackson2JsonMessageConverter serialized object)
note: com.com in this article fasterxml. Jackson uses a dependent version number of 2.9 10. Do not use the latest version 2.12 4. It is better to use the latest version of Spring Boot and redis (currently 2.5.2), and keep the two versions consistent to avoid incompatibility.
about this configuration class: the reply mode is the manual confirmation mode. If the message cannot be matched to the queue through the exchange, it will be returned to the producer. Message serialization is supported. The code has comments, which you can study carefully.
SimpleRabbitMqConfig.java
package com.alian.rabbitmq.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import org.springframework.amqp.core.AcknowledgeMode; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @Configuration public class SimpleRabbitMqConfig { /** * SimpleMessageListenerContainer * * @param connectionFactory * @return */ @Bean(name = "simpleContainerFactory") public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory simpleContainerFactory = new SimpleRabbitListenerContainerFactory(); //Set up connection factory simpleContainerFactory.setConnectionFactory(connectionFactory); //The received message is serialized by Jackson2JsonMessageConverter simpleContainerFactory.setMessageConverter(this.jackson2JsonMessageConverter()); //Set the initial number of consumers (the configuration priority of the SimpleRabbitListenerContainerFactory configuration class is higher than the configuration file) simpleContainerFactory.setConcurrentConsumers(2); //Set the maximum number of consumers (the configuration priority of the SimpleRabbitListenerContainerFactory configuration class is higher than the configuration file) simpleContainerFactory.setMaxConcurrentConsumers(10); //Set the number of messages that consumers get each time. The default is 250 (the configuration priority of simplerabbitlistenercontainerfactory configuration class is higher than that of the configuration file) simpleContainerFactory.setPrefetchCount(30); //The consumer listener throws an exception, whether to return to the queue. The default is true: return to the queue, and false means not to return to the queue (combined with dead letter switch) simpleContainerFactory.setDefaultRequeueRejected(false); //Response mode NONE: unconfirmed mode, MANUAL: MANUAL confirmation mode, AUTO: automatic confirmation mode simpleContainerFactory.setAcknowledgeMode(AcknowledgeMode.MANUAL); return simpleContainerFactory; } @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(); //Set up connection factory rabbitTemplate.setConnectionFactory(connectionFactory); //The received message is serialized by Jackson2JsonMessageConverter (java 8 time is supported) rabbitTemplate.setMessageConverter(this.jackson2JsonMessageConverter()); //When Mandatory is true, messages that cannot be matched to the queue through the exchange will be returned to the producer. When Mandatory is false, messages that cannot be matched will be directly discarded rabbitTemplate.setMandatory(true); return rabbitTemplate; } @Bean("jacksonMessageConverter") public MessageConverter jackson2JsonMessageConverter() { ObjectMapper mapper = getMapper(); return new Jackson2JsonMessageConverter(mapper); } /** * Use COM fasterxml. jackson. databind. ObjectMapper * Data processing, including time in Java 8 * * @return */ private ObjectMapper getMapper() { ObjectMapper mapper = new ObjectMapper(); //Set Visible mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //Default type object mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //Set Java 8 time serialization JavaTimeModule timeModule = new JavaTimeModule(); timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); //Disable time to timestamp mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); //No exception is thrown when an unknown attribute or attribute mismatch is encountered mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.registerModule(timeModule); return mapper; } }
note 1: in the mode with ack, you need to consider setDefaultRequeueRejected(false). Otherwise, when the consumer message throws an exception and does not catch, the message will be pushed back to the queue header by rabbitmq, then thrown an exception and put back... Dead loop. Setting false is used to discard the exception directly instead of putting it back. Therefore, this message may need to be processed to avoid loss.
note 2: when Mandatory is true, messages that cannot be matched to the queue through the exchange will be returned to the producer. When it is false, messages that cannot be matched will be directly discarded
note 3: when configuring the simple container, the configuration priority of the configuration class is higher than that of the configuration file, such as:
SimpleRabbitListenerContainerFactory simpleContainerFactory = new SimpleRabbitListenerContainerFactory(); //Set up connection factory simpleContainerFactory.setConnectionFactory(connectionFactory); //The received message is serialized by Jackson2JsonMessageConverter simpleContainerFactory.setMessageConverter(this.jackson2JsonMessageConverter()); //Set the initial number of consumers (the configuration priority of the SimpleRabbitListenerContainerFactory configuration class is higher than the configuration file) simpleContainerFactory.setConcurrentConsumers(2); //Set the maximum number of consumers (the configuration priority of the SimpleRabbitListenerContainerFactory configuration class is higher than the configuration file) simpleContainerFactory.setMaxConcurrentConsumers(10); //Set the number of messages that consumers get each time. The default is 250 (the configuration priority of simplerabbitlistenercontainerfactory configuration class is higher than that of the configuration file) simpleContainerFactory.setPrefetchCount(30); //Response mode NONE: unconfirmed mode, MANUAL: MANUAL confirmation mode, AUTO: automatic confirmation mode simpleContainerFactory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
The priority of is higher than that configured below
#Minimum number of consumers spring.rabbitmq.listener.simple.concurrency=3 #Maximum number of consumers spring.rabbitmq.listener.simple.max-concurrency=10 #Number of messages per fetch spring.rabbitmq.listener.simple.prefetch=50 #Message confirmation mode: manual/auto/none spring.rabbitmq.listener.simple.acknowledge-mode=manual
4, Consumer (key points)
here I write a consumer that can support the transfer of various objects, such as string, json, HashMap, byte array and user-defined entity objects.
In practice, we have to unify the message transmission mode. If it is a distributed system, it is recommended to adopt the object mode, because different systems may be developed by different people, so that the message content is easy to read and more in line with the java object-oriented development mode.
ConsumeService.java
package com.alian.rabbitmq.service; import com.alian.common.constant.MQConstants; import com.alian.common.dto.Employee; import com.alian.common.dto.PayRecord; import com.alibaba.fastjson.JSONObject; import com.rabbitmq.client.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Service; import java.util.HashMap; @Slf4j @Service @RabbitListener(queues = MQConstants.ALIAN_QUEUE_NAME, containerFactory = "simpleContainerFactory") public class ConsumeService { /** * Note: com alian. common. dto. Employee */ @RabbitHandler public void processEmployee(Employee employee, Channel channel, Message message) throws Exception { log.info("----------Start processing Employee----------"); log.info("Received Employee information: {}", employee); log.info("----------Employee Processing complete----------"); //In case of manual response mode: acknowledge mode Manual needs to be called //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } /** * Note: com alian. common. dto. PayRecord */ @RabbitHandler public void processPayRecord(PayRecord payRecord, Channel channel, Message message) throws Exception { log.info("----------Start processing PayRecord----------"); log.info("channel={}", channel); log.info("message={}", message); log.info("Received PayRecord information: {}", payRecord); log.info("----------PayRecord Processing complete----------"); //In case of manual response mode: acknowledge mode Manual needs to be called //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } @RabbitHandler public void processStr(String str, Channel channel, Message message) throws Exception { log.info("----------Start processing String----------"); log.info("Received string information: {}", str); log.info("----------String Processing complete----------"); //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } @RabbitHandler public void processJson(JSONObject json, Channel channel, Message message) throws Exception{ log.info("----------Start processing JSONObject----------"); log.info("Received JSONObject information: {}", json); log.info("----------JSONObject Processing complete----------"); //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } @RabbitHandler public void processHashMap(HashMap hashMap, Channel channel, Message message) throws Exception{//Can receive messages log.info("----------Start processing HashMap----------"); log.info("Received HashMap information: {}", hashMap); log.info("----------HashMap Processing complete----------"); //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } @RabbitHandler public void processByte(byte[] bytes, Channel channel, Message message) throws Exception{ log.info("----------Start processing byte[]----------"); log.info("Received byte[]information: {}", new String(bytes)); log.info("----------byte[]Processing complete----------"); //deliveryTag: the index of the message; Multiple: batch true: all messages less than deliveryTag will be ack ed at one time. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } }
note:
many people create a wrapper class locally, then copy this class to another system, and send messages, You may never get it (the path of the package may change); in addition, the project sends messages within the project. The project receives messages normally and thinks that it is OK to cross the system. It is not aware of the seriousness of the problem. After the message is serialized, it should be noted that the type of deserialization should have the same name as the package. Otherwise, it will throw an exception that can not be found. This is why I want to send a package to the private server and put it forward to you This is a key issue.
5, Configuration file
I configure here according to the identity of consumers. I won't configure too much about producers. It's unnecessary. Because the configuration of the factory class SimpleRabbitListenerContainerFactory in the simple container has higher priority than the configuration file, and I want to serialize it with jackson2JsonMessageConverter. All of them are configured in my configuration class.
application.properties
#Project name and port server.port=8888 server.servlet.context-path=/simpleRabbitmq #RabbitMQ configuration #address spring.rabbitmq.addresses=192.168.0.194 #port spring.rabbitmq.port=5672 #user name spring.rabbitmq.username=test #password spring.rabbitmq.password=test #The virtual host to use when connecting to the agent spring.rabbitmq.virtual-host=/ #Container type (simple, direct) spring.rabbitmq.listener.type=simple
Running results after starting the project:
2021-07-30 16:25:37 718 [main] INFO logStarting 55:Starting RabbitmqApplication using Java 1.8.0_111 on DESKTOP-EIGL04G with PID 7140 (C:\workspace\study\RabbitMq-simple\target\classes started by admin in C:\workspace\study\RabbitMq-simple) 2021-07-30 16:25:37 720 [main] INFO logStartupProfileInfo 659:No active profile set, falling back to default profiles: default 2021-07-30 16:25:38 375 [main] INFO initialize 108:Tomcat initialized with port(s): 8888 (http) 2021-07-30 16:25:38 382 [main] INFO log 173:Initializing ProtocolHandler ["http-nio-8888"] 2021-07-30 16:25:38 382 [main] INFO log 173:Starting service [Tomcat] 2021-07-30 16:25:38 382 [main] INFO log 173:Starting Servlet engine: [Apache Tomcat/9.0.48] 2021-07-30 16:25:38 433 [main] INFO log 173:Initializing Spring embedded WebApplicationContext 2021-07-30 16:25:38 433 [main] INFO prepareWebApplicationContext 290:Root WebApplicationContext: initialization completed in 683 ms 2021-07-30 16:25:39 053 [main] INFO log 173:Starting ProtocolHandler ["http-nio-8888"] 2021-07-30 16:25:39 064 [main] INFO start 220:Tomcat started on port(s): 8888 (http) with context path '/simpleRabbitmq' 2021-07-30 16:25:39 066 [main] INFO connectAddresses 638:Attempting to connect to: [192.168.0.194:5672] 2021-07-30 16:25:39 129 [main] INFO createBareConnection 589:Created new connection: rabbitConnectionFactory#18137eab:0/SimpleConnection@562919fe [delegate=amqp://test@192.168.0.194:5672/, localPort= 53315] 2021-07-30 16:25:39 208 [main] INFO logStarted 61:Started RabbitmqApplication in 1.776 seconds (JVM running for 2.487)
The following information can be viewed through the RabbitMQ client:
Unfinished to be continued
now that the consumer has finished writing, the next step is to write about the producer. Pay attention to my next article:
Link: RabbitMQ notes (2) spring boot integrates RabbitMQ's simple container (producer).