1. 程式人生 > 其它 >Java微信支付介面使用方法詳解(下)

Java微信支付介面使用方法詳解(下)

AMQP協議

AMQP協議:即Advanced Message Queuing Protocol,是一個應用層標準高階訊息佇列協議,提供統一訊息服務。是應用層協議的一個開放標準,為面向訊息的中介軟體設計。基於此協議的客戶端與訊息中介軟體可傳遞訊息,並不受客戶端/中介軟體不同產品,不同的開發語言等條件的限制。

AMQP中訊息的路由過程和JMS存在一些差別。AMQP中增加了Exchange和Binding的角色。生產者把訊息釋出到Exchange上,訊息最終到達佇列並被消費者接收,而Binding決定交換器的訊息應該傳送到哪個佇列。


RabbitMQ工作原理

rabbitmq整體架構

RabbitMQ各元件功能與核心概念


  • Broker:標識訊息佇列伺服器實體.
  • Virtual Host:虛擬主機。標識一批交換機、訊息佇列和相關物件。虛擬主機是共享相同的身份認證和加密環境的獨立伺服器域。每個vhost本質上就是一個mini版的RabbitMQ伺服器,擁有自己的佇列、交換器、繫結和許可權機制。vhost是AMQP概念的基礎,必須在連結時指定,RabbitMQ預設的vhost是 /。(可以理解成一個數據庫)

  • 生產者(Producer):傳送訊息的應用。
  • 消費者(Consumer):接收訊息的應用。
  • 佇列(Queue):儲存訊息的快取。
  • 訊息(Message):由生產者通過RabbitMQ傳送給消費者的資訊。
  • 連線(Connection):連線RabbitMQ和應用伺服器的TCP連線。
  • 通道(Channel):連線裡的一個虛擬通道。當你通過訊息佇列傳送或者接收訊息時,這個操作都是通過通道進行的。
  • 交換機(Exchange):交換機負責從生產者那裡接收訊息,並根據交換型別分發到對應的訊息列隊裡。要實現訊息的接收,一個佇列必須到繫結一個交換機。
  • 繫結(Binding):繫結是佇列和交換機的一個關聯連線。
  • 路由鍵(Routing Key):路由鍵是供交換機檢視並根據鍵來決定如何分發訊息到列隊的一個鍵。路由鍵可以說是訊息的目的地址。

  • 使用者(Users):在RabbitMQ裡,是可以通過指定的使用者名稱和密碼來進行連線的。每個使用者可以分配不同的許可權,例如讀許可權,寫許可權以及在例項裡進行配置的許可權。(每個使用者有不同的虛擬主機許可權,就像mysql中不同使用者有不同的資料庫許可權一樣)

通訊過程

  1. 生產者(producer)連結到Rabbit MQ Broker,建立connection,開啟channel
  2. 生產者宣告交換機型別,名稱,是否持久化等。
  3. 生產者傳送訊息,並指定訊息是否持久化等屬性和routing key。
  4. 交換機(exchange)接收訊息(message)後根據訊息的routing key路由到跟當前交換機繫結(binding)的相匹配的佇列裡去。
  5. 消費者(consumer)監聽接收到訊息之後開始業務處理,然後傳送一個ack確認告知訊息已經被消費。
  6. RabbitMQ Broker收到ack之後將對應的訊息從佇列裡刪除。

交換機(Exchange)

交換機型別決定了訊息路由模式:從生產者應用上接收訊息,然後根據繫結和路由鍵將訊息傳送到對應的佇列裡。繫結是交換機和佇列之間的一個關係連線。

交換機型別:

  • 直接(Direct):直接交換機通過訊息上的路由鍵直接對訊息進行分發。
  • 扇出(Fanout):一個扇出交換機會將訊息傳送到所有和它進行繫結的佇列上(只看binding,不看路由鍵)。
  • 主題(Topic):這個交換機會將路由鍵和繫結上的模式進行萬用字元匹配。
  • 訊息頭(Headers):訊息頭交換機使用訊息頭的屬性進行訊息路由。(幾乎用不到了)

交換機其他屬性:

durable:持久化,建立交換機/佇列 時指定durable=true,建立訊息指定delivery_mode => 2 的都會存檔,所以服務重啟後會自動恢復。

autoDelete:設定是否自動刪除,當最後一個繫結到Exchange上的佇列刪除後,自動刪除該Exchange,簡單來說也就是如果該Exchange沒有和任何佇列Queue繫結則刪除

internal:設定是否是RabbitMQ內部使用,預設false。如果設定為 true ,則表示是內建的交換器,客戶端程式無法直接傳送訊息到這個交換器中,只能通過交換器路由到交換器這種方式。

RabbitMQ工作模式

簡單模式:一個生產者,一個消費者

簡單流程介紹 流程:
  • 生產者將訊息放入訊息佇列
  • 訊息的消費者監聽訊息佇列,如果佇列中有訊息,就消費掉。訊息被消費之後,自動從佇列中刪除(容易出現訊息還沒有被消費者正確處理,已經從佇列中消失了,造成訊息的丟失)

適合場景:

  • 簡單的聊天系統

work模式:一個生產者,多個消費者,每個消費者獲取到的訊息唯一

work流程介紹

流程:

  • 1、生產者將訊息放入訊息佇列
  • 多個訊息的消費者同時監聽訊息佇列內容,誰先拿到誰負責消費訊息(高併發情況下,預設會產生某一個訊息被多個消費者共同使用,可以設定一個開關,保證一條訊息只能被一個消費者使用)

適合場景:

  • 搶紅包
  • 隨機分派任務

訂閱模式(p/s):一個生產者傳送的訊息會被多個消費者獲取,且訊息相同。可以理解為type=fanout。

訂閱模式介紹

流程:

  • 1、訊息產生者將訊息放入交換機
  • 2、交換機發布訂閱把訊息傳送到所有訊息佇列中,對應訊息佇列的消費者拿到訊息進行消費

適合場景:

  • 郵件下發
  • 場景訂閱
  • 簡訊下發

路由模式:傳送的訊息到交換機並且要指定路由key,消費者將佇列繫結到交換機時需要指定路由key(這個就是交換機控制的路由模式)

路由模式介紹

流程:

  • 1、訊息生產者將訊息傳送給交換機
  • 2、交換機根據Routing key,只能匹配上Routing key對應的訊息佇列,對應的消費者才能消費訊息;

路由模式和訂閱模式比較相似,只是路由模式模式要求佇列在繫結交換機時要指定Routing key,訊息會轉發到符合Routing key的佇列。

適合場景:

  • 郵件下發
  • 場景訂閱
  • 簡訊下發

主題模式:將路由鍵和某模式進行匹配,此時佇列需要繫結在一個模式上,‘#’匹配一個詞或者多個詞,‘*’匹配一個詞

主題模式介紹

流程:

  • 1、訊息產生者產生訊息,把訊息交給交換機
  • 2、交換機根據key的規則模糊匹配到對應的佇列,由佇列的監聽消費者接收訊息消費,每個消費者監聽自己的佇列,並且設定帶統配符的routingkey

適合場景:

  • 使用者通知的各種情況

多個佇列訊息釋出圖:

RabbitMQ消費模式

  • PUSH:RabbitMQ將訊息主動推送給消費者

註冊一個消費者後,RabbitMQ會在訊息可用時,自動將訊息進行推送給消費者。這種方式效率最高最及時

channel.basic_consume(queuename,autoAck=true,callback() )

  • PULL:消費者去拉取訊息

屬於一種輪詢模型,傳送一次get請求,獲得一個訊息。如果此時RabbitMQ中沒有訊息,會獲得一個表示空的回覆。channel.basic_get(queuename,autoAck=true)

  • ack(Message acknowledgment):訊息確認機制
    自動確認機制autoAck=true,則消費者拿到訊息後這條訊息直接被rabbitMQ從佇列中刪除。
    手動確認機制autoAck=false,這種一般是為了保證訊息成功完成消費。那就需要開發同學在訊息成功消費後新增一個手動確認邏輯channel.basic_ack(delivery_tag=method.delivery_tag())
    沒有ack會發生什麼,這條訊息不會刪除,繼續發給下一個消費者消費。
    https://www.rabbitmq.com/tutorials/tutorial-two-python.html

RabbitMQ專案實踐

【加好友配額中心】專案中,需要對使用者做的操作實時的給予獎勵。比如【處理好友資訊】:每天及時處理好友資訊,我們會給使用者發5個好友額度獎勵。

好友額度跟待處理髮生了以下對話:

不屬於一個功能模組,耦合性太高,維護困難,理解困難。而且使用者只是處理一個請求,不需要把計算獎勵額度的時間累加給待處理請求(待處理表示不同意!)

這時候,開發同學就想到了訊息中介軟體~~~

待處理請求後,發一條訊息到MQ。好友額度定時從MQ拿訊息,拿到後就知道是使用者處理了請求。再去做相應的額度獎勵處理。這就不會有上面的問題了。

具體的message就根據業務需求來填充了。多種獎勵型別,每種獎勵都有一個自己的佇列,所以需要使用routing_key屬性;

釋出訊息:

msg={"uid2": 138262752, "uid": 138262060, "accepted": 3, "type": 1, "id": 46374, "frm": null, "ts": 1603178783.451986}

manager.mq2.publish_user_action(msg=msg, routing_key='network_contact_request_finished')

>>>>>>MQueue.publish(msg=msg,exchange='user_action',routing_key=routing_key) //釋出訊息的話,需要exchange,跟routing_key

接收訊息:

from mmsdk.models.mqueue import MQueue
mqueue = MQueue(host=host, port=port, user=user, passwd=password)

msg = mqueue.basic_get(name='user_action_network_request_finished',no_ack=no_ack) //從佇列取訊息的話是直接根據queue_name拿訊息。