RabbitMQ與Spring的框架整合之Spring Boot實戰

1、RabbitMQ與Spring的框架整合之Spring Boot實戰。

首先創建maven項目的RabbitMQ的消息生產者rabbitmq-springboot-provider項目,配置pom.xml配置文件,如下所示:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
 4     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <groupId>com.bie</groupId>
 7     <artifactId>rabbitmq-springboot-provider</artifactId>
 8     <version>0.0.1-SNAPSHOT</version>
 9 
10     <parent>
11         <groupId>org.springframework.boot</groupId>
12         <artifactId>spring-boot-starter-parent</artifactId>
13         <version>2.0.2.RELEASE</version>
14         <relativePath /> <!-- lookup parent from repository -->
15     </parent>
16 
17     <properties>
18         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20         <java.version>1.8</java.version>
21     </properties>
22 
23     <dependencies>
24         <dependency>
25             <groupId>org.springframework.boot</groupId>
26             <artifactId>spring-boot-starter</artifactId>
27         </dependency>
28 
29         <dependency>
30             <groupId>org.springframework.boot</groupId>
31             <artifactId>spring-boot-starter-test</artifactId>
32             <scope>test</scope>
33         </dependency>
34         <dependency>
35             <groupId>org.springframework.boot</groupId>
36             <artifactId>spring-boot-starter-amqp</artifactId>
37         </dependency>
38     </dependencies>
39 
40     <build>
41         <plugins>
42             <plugin>
43                 <groupId>org.springframework.boot</groupId>
44                 <artifactId>spring-boot-maven-plugin</artifactId>
45             </plugin>
46         </plugins>
47     </build>
48 
49 </project>

修改rabbitmq-springboot-provider的配置文件application.yml,如下所示:

 1 spring:
 2   rabbitmq:
 3     addresses: 192.168.110.133:5672 # rabbitmq服務器的ip地址和端口號
 4     username: guest                 # rabbitmq服務器的賬號
 5     password: guest                 # rabbitmq服務器的密碼
 6     virtual-host: /                 # rabbitmq服務器的虛擬主機      
 7     connection-timeout:
 8       15000                         # rabbitmq服務器連接超時時間
 9     # publisher-confirms,實現一個監聽器用於監聽Broker端給我們返回的確認請求。RabbitTemplate.ConfirmCallback。  
10     publisher-confirms: true        # 消息確認模式
11     # publisher-returns,保證消息對Broker端是可達的,如果出現路由鍵不可達的情況,
12     # 則使用監聽器對不可達的消息進行後續處理,保證消息的路由成功,RabbitTemplate.ReturnCallback
13     publisher-returns: true         # 消息返回模式
14     template: 
15       mandatory: true               # 配置mandatory=true保證監聽有效。
16       

創建配置類,可以將bean添加到容器中,開啓註解掃描。

 1 package com.bie.config;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.context.annotation.Configuration;
 5 
 6 /**
 7  * 
 8  * @author biehl
 9  *
10  */
11 @Configuration // 配置類,可以將bean添加到容器中
12 @ComponentScan(basePackages = { "com.bie.*" }) // 掃描包註解
13 public class RabbitMQProducerConfig {
14 
15 }

創建實體類,用於測試消息的發送。

 1 package com.bie.po;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6  * 
 7  * @author biehl
 8  *
 9  */
10 public class Order implements Serializable {
11 
12     /**
13      * 
14      */
15     private static final long serialVersionUID = 1L;
16 
17     private String id;
18     private String name;
19 
20     public String getId() {
21         return id;
22     }
23 
24     public void setId(String id) {
25         this.id = id;
26     }
27 
28     public String getName() {
29         return name;
30     }
31 
32     public void setName(String name) {
33         this.name = name;
34     }
35 
36     public Order(String id, String name) {
37         super();
38         this.id = id;
39         this.name = name;
40     }
41 
42     @Override
43     public String toString() {
44         return "Order [id=" + id + ", name=" + name + "]";
45     }
46 
47     public Order() {
48         super();
49     }
50 
51 }

創建RabbitMQ的生產者,用於消息的發送。

  1 package com.bie.producer;
  2 
  3 import java.text.SimpleDateFormat;
  4 import java.util.Date;
  5 import java.util.Map;
  6 import java.util.UUID;
  7 
  8 import org.springframework.amqp.rabbit.core.RabbitTemplate;
  9 import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
 10 import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
 11 import org.springframework.amqp.rabbit.support.CorrelationData;
 12 import org.springframework.beans.factory.annotation.Autowired;
 13 import org.springframework.messaging.Message;
 14 import org.springframework.messaging.MessageHeaders;
 15 import org.springframework.messaging.support.MessageBuilder;
 16 import org.springframework.stereotype.Component;
 17 
 18 import com.bie.po.Order;
 19 
 20 /**
 21  * 
 22  * @author biehl
 23  *
 24  */
 25 @Component
 26 public class RabbitMQProducerMessage {
 27 
 28     @Autowired
 29     private RabbitTemplate rabbitTemplate;
 30 
 31     // publisher-confirms,實現一個監聽器用於監聽Broker端給我們返回的確認請求。RabbitTemplate.ConfirmCallback。
 32     // publisher-returns,保證消息對Broker端是可達的,如果出現路由鍵不可達的情況,則使用監聽器對不可達的消息進行後續處理,保證消息的路由成功,RabbitTemplate.ReturnCallback
 33     // 注意:在發送消息的時候對template進行配置mandatory=true保證監聽有效。
 34     // 生產端還可以配置其他屬性,比如發送重試、超時時間、次數、間隔等等。
 35 
 36     // 回調函數,confirm確認
 37     final ConfirmCallback confirmCallback = new ConfirmCallback() {
 38 
 39         @Override
 40         public void confirm(CorrelationData correlationData, boolean ack, String cause) {
 41             System.out.println("correlationData : " + correlationData);
 42             System.out.println("ack : " + ack);
 43             if (!ack) {
 44                 System.out.println("異常處理,將後續繼續處理.......");
 45             }
 46             System.out.println();
 47         }
 48 
 49     };
 50 
 51     // 回調函數,return返回
 52     final ReturnCallback returnCallback = new ReturnCallback() {
 53 
 54         @Override
 55         public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText,
 56                 String exchange, String routingKey) {
 57             System.err.println("return exchange: " + exchange + ", routingKey: " + routingKey + ", replyCode: "
 58                     + replyCode + ", replyText: " + replyText);
 59         }
 60 
 61     };
 62 
 63     /**
 64      * 發送消息的方法
 65      * 
 66      * @param message
 67      * @param properties
 68      */
 69     public void send(Object message, Map<String, Object> properties) {
 70         // 設置消息頭信息
 71         MessageHeaders messageHeaders = new MessageHeaders(properties);
 72         // 創建消息
 73         Message msg = MessageBuilder.createMessage(message, messageHeaders);
 74         // 消息確認和消息返回機制的回調
 75         rabbitTemplate.setConfirmCallback(confirmCallback);
 76         rabbitTemplate.setReturnCallback(returnCallback);
 77         // id + 時間戳的格式,保證全局唯一性
 78         CorrelationData correlationData = new CorrelationData();
 79         String id = UUID.randomUUID().toString();
 80         // 唯一性id,做ack可靠性投遞的時候、補償策略的時候,根據該id可以找到唯一條消息。
 81         correlationData.setId(id);
 82         String exchange = "exchange-1"; // 交換機名稱。需要自己創建好該交換機,然後創建一個隊列,使用路由鍵將該交換機和隊列進行綁定即可。
 83         String routingkey = "springboot.helloRabbitmq"; // 路由鍵
 84         rabbitTemplate.convertAndSend(exchange, routingkey, msg, correlationData);
 85     }
 86 
 87     /**
 88      * 
 89      * @param order
 90      */
 91     public void sendOrder(Order order) {
 92         // 消息確認和消息返回機制的回調
 93         rabbitTemplate.setConfirmCallback(confirmCallback);
 94         rabbitTemplate.setReturnCallback(returnCallback);
 95         // id + 時間戳的格式,保證全局唯一性
 96         CorrelationData correlationData = new CorrelationData();
 97         String id = UUID.randomUUID().toString();
 98         correlationData.setId(id);
 99         rabbitTemplate.convertAndSend("exchange-1", "springboot.def", order, correlationData);
100     }
101 
102 }

創建主啓動類,進行項目的啓動,如下所示:

 1 package com.bie;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 
 6 /**
 7  * 
 8  * @author biehl
 9  *
10  */
11 @SpringBootApplication
12 public class SpringBootRabbitMQProviderApplication {
13 
14     public static void main(String[] args) {
15         SpringApplication.run(SpringBootRabbitMQProviderApplication.class, args);
16     }
17 
18 }

創建生產者的測試類,進行生產者消息的發送。

 1 package com.bie.springboot;
 2 
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5 import java.util.HashMap;
 6 import java.util.Map;
 7 
 8 import org.junit.Test;
 9 import org.junit.runner.RunWith;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.boot.test.context.SpringBootTest;
12 import org.springframework.test.context.junit4.SpringRunner;
13 
14 import com.bie.po.Order;
15 import com.bie.producer.RabbitMQProducerMessage;
16 
17 @RunWith(SpringRunner.class)
18 @SpringBootTest
19 public class ApplicationTests {
20 
21     @Autowired
22     private RabbitMQProducerMessage rabbitMQProducerMessage;
23 
24     private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
25 
26     @Test
27     public void rabbitMQProducerMessage() throws Exception {
28         Map<String, Object> properties = new HashMap<>();
29         properties.put("idCard", "410725195545815685x");
30         properties.put("createdate", simpleDateFormat.format(new Date()));
31         for (int i = 0; i < 1000; i++) {
32             rabbitMQProducerMessage.send("Hello RabbitMQ For Spring Boot!" + i, properties);
33         }
34 
35         // 線程休眠,消息ack確認
36         // Thread.sleep(500000);
37     }
38 
39     @Test
40     public void rabbitMQProducerOrder() throws Exception {
41         Order order = new Order("001", "第一個訂單");
42         rabbitMQProducerMessage.sendOrder(order);
43     }
44 
45 }

生產者發送消息,可以在RabbitMQ的管控臺進行觀察效果的。上面這種方式,需要手動創建交換機,隊列,以及使用路由鍵將交換機和隊列進行綁定。可以在管控臺進行交換機、隊列、以及使用路由鍵將交換機和隊列進行綁定的。

2、首先創建maven項目的RabbitMQ的消息消費者rabbitmq-springboot-consumer項目,配置pom.xml配置文件,如下所示:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
 4     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <groupId>com.bie</groupId>
 7     <artifactId>rabbitmq-springboot-consumer</artifactId>
 8     <version>0.0.1-SNAPSHOT</version>
 9 
10     <parent>
11         <groupId>org.springframework.boot</groupId>
12         <artifactId>spring-boot-starter-parent</artifactId>
13         <version>2.0.2.RELEASE</version>
14         <relativePath /> <!-- lookup parent from repository -->
15     </parent>
16 
17     <properties>
18         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20         <java.version>1.8</java.version>
21     </properties>
22 
23     <dependencies>
24         <dependency>
25             <groupId>org.springframework.boot</groupId>
26             <artifactId>spring-boot-starter</artifactId>
27         </dependency>
28 
29         <dependency>
30             <groupId>org.springframework.boot</groupId>
31             <artifactId>spring-boot-starter-test</artifactId>
32             <scope>test</scope>
33         </dependency>
34         <dependency>
35             <groupId>org.springframework.boot</groupId>
36             <artifactId>spring-boot-starter-amqp</artifactId>
37         </dependency>
38     </dependencies>
39 
40     <build>
41         <plugins>
42             <plugin>
43                 <groupId>org.springframework.boot</groupId>
44                 <artifactId>spring-boot-maven-plugin</artifactId>
45             </plugin>
46         </plugins>
47     </build>
48 
49 </project>

由於生產者端和消費者端是分項目開發的,但是配置類RabbitMQProducerConfig和實體類Order都一樣,主啓動類修改一下名稱即可,這裏就省略了。

 1 package com.bie.consumer;
 2 
 3 import java.util.Map;
 4 
 5 import org.springframework.amqp.rabbit.annotation.Exchange;
 6 import org.springframework.amqp.rabbit.annotation.Queue;
 7 import org.springframework.amqp.rabbit.annotation.QueueBinding;
 8 import org.springframework.amqp.rabbit.annotation.RabbitHandler;
 9 import org.springframework.amqp.rabbit.annotation.RabbitListener;
10 import org.springframework.amqp.support.AmqpHeaders;
11 import org.springframework.messaging.Message;
12 import org.springframework.messaging.handler.annotation.Headers;
13 import org.springframework.messaging.handler.annotation.Payload;
14 import org.springframework.stereotype.Component;
15 
16 import com.bie.po.Order;
17 import com.rabbitmq.client.Channel;
18 
19 /**
20  * 
21  * @author biehl
22  * 
23  *         1、簽收模式,首先配置手動確認模式,用於ack的手工處理,這樣我們可以保證消息的可靠性送達,
24  *         或者在消費端消費失敗的時候可以做到重回隊列,根據業務記錄日誌等處理。
25  * 
26  *         2、可以設置消費端的監聽個數和最大個數,用於控制消費端的併發情況
27  * 
28  *         3、消費端最重要的就是註解@RabbitListener註解的使用。消息端監聽註解。
29  * 
30  *         該註解是一個組合註解,裏面可以註解配置@QueueBinding、@Queue、@Exchange。
31  * 
32  *         直接通過這個組合註解一次性搞定消費端交換機、隊列、綁定、路由、並且配置監聽功能等等。
33  * 
34  */
35 @Component
36 public class RabbitMQConsumerMessage {
37     
38     @RabbitListener(bindings = @QueueBinding(
39 
40             value = @Queue(value = "${order.queue.name}", durable = "${order.queue.durable}"),
41 
42             exchange = @Exchange(value = "${order.exchange.name}", durable = "${order.exchange.durable}", type = "${order.exchange.type}", ignoreDeclarationExceptions = "${order.exchange.ignoreDeclarationExceptions}"),
43 
44             key = "${order.key}"
45 
46             )
47 
48     )
49     @RabbitHandler
50     public void onMessage(Message message, Channel channel) throws Exception {
51         System.out.println("消費者: " + message.getPayload());
52         Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
53         // 手工ack
54         channel.basicAck(deliveryTag, false);
55     }
56 
57     /**
58      * 
59      * order.queue.name=queue-2 order.queue.durable=true
60      * order.exchange.name=exchange-1 order.exchange.durable=true
61      * order.exchange.type=topic order.exchange.ignoreDeclarationExceptions=true
62      * order.key=springboot.*
63      * 
64      * @param order
65      * @param channel
66      * @param headers
67      * @throws Exception
68      */
69     @RabbitListener(bindings = @QueueBinding(
70 
71             value = @Queue(value = "${order.queue.name}", durable = "${order.queue.durable}"),
72 
73             exchange = @Exchange(value = "${order.exchange.name}", durable = "${order.exchange.durable}", type = "${order.exchange.type}", ignoreDeclarationExceptions = "${order.exchange.ignoreDeclarationExceptions}"),
74 
75             key = "${order.key}"
76 
77             )
78 
79     )
80     @RabbitHandler // @Payload指定實際消息體內容,可以定義到形參上。
81     public void onOrderMessage(@Payload Order order, Channel channel, @Headers Map<String, Object> headers)
82             throws Exception {
83         System.out.println("消費端order: " + order.getId());
84         Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
85         // 手工ACK
86         channel.basicAck(deliveryTag, false);
87     }
88 
89 }

直接啓動消費者的啓動類,然後在生產者測試類開始發送消息,消費端就可以監聽到了消息。

作者:別先生

博客園:https://www.cnblogs.com/biehongli/

如果您想及時得到個人撰寫文章以及著作的消息推送,可以掃描上方二維碼,關注個人公衆號哦。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章