Java Spring boot 整合RabbitMQ(三):(Publish/Subscribe)-B2B2C小程式電子商務
在本篇教程中,我們要做的跟之前完全不一樣 —— 分發一個訊息給多個消費者(consumers)。這種模式被稱為” 釋出 / 訂閱”。
交換器(Exchanges)
在本教程的前面部分,我們傳送和接收到佇列中的訊息,現在是時候在 RabbitMQ 中引入完整的訊息傳遞模式了。
讓我們快速回顧一下之前瞭解的內容:
生產者(producer):傳送訊息的程式
佇列(queue):儲存訊息的緩衝器
消費者(consumer):接收訊息的程式
RabbitMQ 訊息模型的核心理念是:釋出者(producer)不會直接傳送任何訊息給佇列。事實上,釋出者(producer)甚至不知道訊息是否已經被投遞到佇列。
釋出者(producer)只需要把訊息傳送給一個交換器(exchange)。交換器非常簡單,它一邊從釋出者方接收訊息,一邊把訊息推送到佇列。交換器必須知道如何處理它接收到的訊息,是應該推送到指定的佇列還是多個佇列,或者是直接忽略訊息。這些規則是透過交換器型別(exchange type)來定義的。
有幾個可供選擇的交換器型別:direct, topic, headers 和 fanout。我們在這裡主要說明最後一個 ——fanout。fanout exchange 很簡單,你可能從名字上就能猜測出來,它把訊息傳送給它所知道的所有佇列。這正是我們所需要的。
先建立一個 fanout 型別的交換器,命名為”tut.fanout”
@Profile({"tut3", "pub-sub"}) @Configuration public class Tut3Config { /** * 定義一個 Exchange * * @return FanoutExchange */ @Bean public FanoutExchange queue() { return new FanoutExchange("tut.fanout"); } /** * 消費者一端的配置:queues、bindings */ @Profile("receiver") private static class ReceiverConfig { @Bean public Queue autoDeleteQueue1() { return new AnonymousQueue(); } @Bean public Queue autoDeleteQueue2() { return new AnonymousQueue(); } @Bean public Binding binding1(FanoutExchange fanout, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1).to(fanout); } @Bean public Binding binding2(FanoutExchange fanout, Queue autoDeleteQueue2) { return BindingBuilder.bind(autoDeleteQueue2).to(fanout); } @Bean public Tut3Receiver receiver() { return new Tut3Receiver(); } } @Bean @Profile("sender") public Tut3Sender sender() { return new Tut3Sender(); } }
和之前的兩個教程一樣,我們定義了兩個 profiles(tut3、pub-sub)以保證我們能執行指定的示例。然後建立了一個消費者端的配置,並在其中定義了兩個 AnonymousQueue 和兩個 Binding 以便將相應的佇列和交換器繫結起來。
交換器列表
rabbitmqctl 能夠列出伺服器上所有的交換器。這個列表中有一些叫做 amq.* 的交換器。這些都是預設建立的,不過這時候你還不需要使用他們。
$ sudo rabbitmqctl list_exchanges
Listing exchanges …
logs fanout
amq.direct direct
amq.topic topic
amq.fanout fanout
amq.headers headers
…done.
未命名交換器(Nameless exchange)
在之前,我們對交換一無所知,但依然能夠將訊息傳送到佇列。這是怎麼回事?因為我們使用了預設的交換器,它是用空字串(””)來標識的。
我們之前是這樣傳送訊息的:
template.convertAndSend(queue.getName(), message);
而具體原始碼如下,可以看出之前我們使用的是預設的空字元定義的交換器
// RabbitTemplate @Override public void convertAndSend(String routingKey, final Object object) throws AmqpException { convertAndSend(this.exchange, routingKey, object, (CorrelationData) null); } private volatile String exchange = DEFAULT_EXCHANGE; /\*_ Alias for amq.direct default exchange. _/ private static final String DEFAULT_EXCHANGE = "";
臨時佇列(Temporary queues)
我們之前使用的是具有指定名稱的佇列(hello 和 work-queues)。能夠命名佇列對我們而言至關重要 —— 我們需要將工作程式指向同一個佇列。當我們想要在生產者和消費者之間共享佇列時,給佇列一個名字很重要。
但是我們的日誌記錄器並不是這樣。我們希望記錄到所有的日誌訊息,而不僅僅是它們的一部分。我們也只對當前的訊息感興趣,而對舊的訊息不感興趣。為了解決這個問題,我們需要做兩件事情。
首先,每當我們連線到 RabbitMQ,我們需要一個新的空的佇列。我們可以建立一個具有隨機名稱的佇列,或者最好讓伺服器為我們選擇一個隨機的佇列名。
其次,當與消費者(consumer)斷開連線的時候,這個佇列應當被立即刪除。
在 Spring AMQP 中,我們可以使用 AnonymousQueue 來作為臨時佇列。它是一個非持久化的、獨佔的、可自動刪除的佇列。
@Bean public Queue autoDeleteQueue1() { return new AnonymousQueue(); } @Bean public Queue autoDeleteQueue2() { return new AnonymousQueue(); }
此時我們的佇列名字看起來會像這樣:amq.gen-JzTY20BRgKO-HjmUJj0wLg
繫結(Bindings)
我們已經建立了一個 fanout exchange 和兩個佇列,現在我們需要告訴交換所將訊息傳送到我們的佇列。交換器和佇列之間的關係稱為繫結。在上面的 Tut3Config 中,您可以看到我們有兩個繫結,每個 AnonymousQueue 都有一個繫結。
@Bean public Binding binding1(FanoutExchange fanout, Queue autoDeleteQueue1) { return BindingBuilder.bind(autoDeleteQueue1).to(fanout); }
繫結列表
你可以使用 rabbitmqctl list_bindings 列出所有現存的繫結。
rabbitmqctl list_bindings
程式碼整合
生產者
發出訊息的生產者程式與以前的沒有多大區別。最重要的變化是我們現在要釋出訊息給我們的 fanout exchange,而不是預設的交換器。傳送時我們需要提供一個 routingKey,但是對於 fanout exchange,這個值將被忽略。
public class Tut3Sender { @Autowird private AmqpTemplate template; @Override private FanoutExchange fanout; private int dots = 0; private int count = 0; @Scheduled(fixedDelay = 1000, initialDelay = 500) public void send() { StringBuilder builder = new StringBuilder("Hello"); if (dots++ == 3) { dots = 1; } for (int i = 0; i < dots; i++) { builder.append('.'); } builder.append(Integer.toString(++count)); String message = builder.toString(); template.convertAndSend(fanout.getName(), "", message); System.out.println(" [x] Sent '" + message + "'"); } }
說明:
禁止釋出到不存在的交換器
如果沒有任何佇列繫結到交換器,訊息將丟失
消費者 瞭解springcloud架構可以加求求:三五三六二四七二五九
我們定義兩個消費者分別監聽兩個佇列
public class Tut3Receiver { @RabbitListener(queues = "#{autoDeleteQueue1.name}") public void receiver1(String in) throws InterruptedException { receive(in, 1); } @RabbitListener(queues = "#{autoDeleteQueue2.name}") public void receiver2(String in) throws InterruptedException { receive(in, 2); } private void receive(String in, int instance) throws InterruptedException { StopWatch watch = new StopWatch(); watch.start(); System.out.println("instance " + instance + " [x] Received '" + in + "'"); doWork(in); watch.stop(); System.out.println("instance " + instance + " [x] Done in " + watch.getTotalTimeSeconds() + "s"); } private void doWork(String in) throws InterruptedException { for (char ch : in.toCharArray()) { if (ch == '.') { Thread.sleep(1000); } } } }
執行
maven 編譯
mvn clean package -Dmaven.test.skip=true
1
2
執行(建議先執行消費者,再執行生產者)
java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut3,receiver --tutorial.client.duration=60000
java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut3,sender --tutorial.client.duration=60000
1
2
3
輸出
// Sender
Ready … running for 60000ms
[x] Sent ‘Hello.1’
[x] Sent ‘Hello…2’
[x] Sent ‘Hello…3’
// Receiver
Ready … running for 60000ms
instance 2 [x] Received ‘Hello.1’
instance 1 [x] Received ‘Hello.1’
instance 2 [x] Done in 1.002s
instance 1 [x] Done in 1.002s
instance 2 [x] Received ‘Hello…2’
instance 1 [x] Received ‘Hello…2’
instance 2 [x] Done in 2.003s
instance 1 [x] Done in 2.003s
instance 1 [x] Received ‘Hello…3’
instance 2 [x] Received ‘Hello…3’
instance 1 [x] Done in 3.011s
instance 2 [x] Done in 3.011s
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952307/viewspace-2678806/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java Spring Boot 整合RabbitMQ(一):Hello World -B2B2C小程式電子商務JavaSpring BootMQ
- Java Spring boot 整合RabbitMQ(五):主題(Topics)-B2B2C小程式電子商務JavaSpring BootMQ
- Java Spring boot 整合RabbitMQ(二):工作佇列(Work queues)-B2B2C小程式電子商務JavaSpring BootMQ佇列
- Java Springboot整合RabbitMQ(六):(RPC)-b2b2c小程式電子商務JavaSpring BootMQRPC
- Java Springboot 整合RabbitMQ(四):路由(Routing)-B2B2C小程式電子商務JavaSpring BootMQ路由
- JAVA spring cloud boot b2b2c電子商務分散式微服務JavaSpringCloudboot分散式微服務
- java Spring Cloud b2b2c o2o 電子商務 Eureka【Finchley 版】-b2b2c小程式電子商務JavaSpringCloud
- RabbitMQ系列教程之三:釋出/訂閱(Publish/Subscribe)MQ
- RabbitMQ(三):RabbitMQ與Spring Boot簡單整合MQSpring Boot
- java版 spring cloud spring boot mybatis實現 b2b2c 多商戶電子商務平臺JavaCloudSpring BootMyBatis
- SpringCloud分散式微服務b2b2c電子商務(十三)Springboot整合RabbitMQGCCloud分散式微服務Spring BootMQ
- Spring Boot整合rabbitmqSpring BootMQ
- Spring Boot 整合 rabbitmqSpring BootMQ
- JAVA商城 B2B2C商城系統 小程式 電子商務 springcloud商城JavaSpringGCCloud
- spring cloud spring boot 構建java版 分散式微服務 b2b2c o2o電子商務雲商平臺CloudSpring BootJava分散式微服務
- spring cloud構建java版 b2b2c電子商務雲商平臺SpringCloudJava
- SpringCloud分散式微服務b2b2c電子商務-Spring Boot配置檔案詳解GCCloud分散式微服務Spring Boot
- (十四)JAVA springboot微服務b2b2c電子商務系統- Spring Cloud構建分散式電子商務平臺JavaSpring Boot微服務Cloud分散式
- spring boot-整合RabbitMq(RabbitMq基礎)Spring BootMQ
- Spring Boot 整合 RabbitMQ 訊息事務(消費者)Spring BootMQ
- 電子商務Java微服務 SpringBoot整合SpringSecurityJava微服務Spring BootGse
- JAVA b2b2c電子商務SpringCloud分散式微服務spring-security-基本JavaSpringGCCloud分散式微服務
- java B2B2C原始碼電子商務平臺---大話Spring CloudJava原始碼SpringCloud
- spring cloud+spring boot 電子商務-spring boot 引用方式${}和@@用法與區別CloudSpring Boot
- java B2B2C原始碼電子商務平臺Java原始碼
- spring cloud+spring boot 電子商務spring boot獲取配置檔案的屬性CloudSpring Boot
- java B2B2C 仿淘寶電子商城系統-Spring Cloud構建分散式電子商務平臺JavaSpringCloud分散式
- spring-boot-route(十三)整合RabbitMQSpringbootMQ
- Next.js+Spring boot開源電子商務專案JSSpring Boot
- java B2B2C電子商務平臺分析之七-Spring Cloud ConfigJavaSpringCloud
- java B2B2C springmvc mybatis電子商務平臺原始碼-Spring Cloud SecurityJavaSpringMVCMyBatis原始碼Cloud
- ZeroMQ的模式-Publish-SubscribeMQ模式
- Springcloud分散式微服務b2b2c電子商務一整合Hystrix(二)SpringGCCloud分散式微服務
- java b2b2c電子商務 springcloud分散式微服務-Session共享JavaSpringGCCloud分散式微服務Session
- java B2B2C電子商務平臺------服務閘道器zuulJavaZuul
- java B2B2C Springcloud電子商務平臺原始碼JavaSpringGCCloud原始碼
- 電子商務平臺 java b2b2c o2oJava
- RabbitMQ訊息佇列(四):分發到多Consumer(Publish/Subscribe)MQ佇列