Spring Cloud Stream 2.0 - 內容類型協商與轉換

工程 | Oleg Zhurakousky | 2018 年 2 月 26 日 | ...

這是 Spring Cloud Stream 2.0.0.RELEASE 準備階段中一系列預先發佈部落格的第一篇。

前言

Spring Cloud Stream 2.0 包含針對基於通道的繫結器的內容類型協商進行了徹底的修改,以解決效能、彈性,以及最重要的是一致性。 以下部落格文章將觸及關於已完成的工作、預期以及它可能如何協助您的一些關鍵要點。

簡介

資料轉換是任何訊息驅動微服務架構的核心功能之一。 在 Spring Cloud Stream 中,此類資料表示為 Spring Message

在訊息流程(串流)的各個點,訊息可能必須在到達其目的地之前轉換為所需的形狀/大小。 這是由於兩個原因而需要的

1. 將傳入訊息的內容線路格式轉換,以符合應用程式提供的處理常式的簽章。 2. 將傳出訊息的內容轉換為下一個處理常式的簽章(如果存在一些內部流程)或轉換回線路格式。

線路格式通常是 byte[],並且由繫結器實作管理。

在 Spring Cloud Stream Message 中,轉換是使用 org.springframework.messaging.converter.MessageConverter 抽象化完成的。

以下步驟順序顯示了典型的訊息流程以及 Message 經歷的轉換,使用 Spring Cloud Stream 的 Processor 合約描述,本質上涵蓋了輸入輸出內容轉換背後的要求。

1. 從繫結器接收線路格式的 Spring Message 2. 確保在 Spring Message 中設定了輸入 contentType 標頭 3. 將 Spring Message 線路格式轉換為應用程式提供的 MessageHandler 的簽章 4. 呼叫應用程式提供的 MessageHandler 5. 將 MessageHandler 的傳回值轉換回 Spring Message 6. 確保在 Spring Message 中設定了輸出 contentType 標頭 7. 將 Spring Message 轉換回線路格式 8. 以線路格式將 Spring Message 送回繫結器

雖然以上內容提供了典型訊息流程中主要狀態變更的完整摘要,但魔鬼總是在細節中,所以讓我們更仔細地查看每個步驟。

詳細資訊

  1. 傳入訊息由繫結器接收,並以線路格式傳送到繫結器的輸入通道(例如,Processor.INPUT')。
  2. 內部輸入通道預先配置了一個通道攔截器,以將 contentType 標頭注入到傳入訊息中,當且僅當傳入訊息尚未設定 contentType 標頭時。 這是必需的,以確保在需要時,下游訊息轉換可以將 contentType 納入考量(稍後會詳細介紹)。 注入的 contentType 來自每個目的地繫結設定的內容類型application/json 是預設內容類型。

例如,'spring.cloud.stream.bindings.myInput.content-type=text/plain' 將 'myInput'(傳入)目的地繫結的內容類型設定為 'text/plain'。 這表示每個傳入訊息都會注入 'contentType=text/plain' 標頭,除非該訊息已經包含 'contentType' 標頭。 換句話說,標頭提供的 contentType 取代每個繫結設定的那個。 3. 現在,借助於 HandlerMethodArgumentResolvers 和預先配置或使用者提供的 MessageConverters,傳入訊息會被轉換為應用程式提供的 MessageHandler 的簽章(例如,public Text process(Foo foo){..})。 此類處理常式方法通常使用 @StreamListener@ServiceActivator@Transformer 等註解。 這是某些轉換器可能需要 contentType 的地方,步驟 2 中的動作可確保此類訊息始終透過其 contentType 標頭可用。 當然,如果此類方法採用 Message 作為其輸入引數,則不會執行轉換。 4. 呼叫處理常式方法,成功後,便開始從處理常式方法的傳回值建立傳出訊息的過程(假設是非 void 處理常式方法)。 5. 僅當傳回值還不是 Message 時,處理常式方法傳回的值才會轉換回 Spring Message。 這表示會建立一個新的 Spring Message,其有效負載是處理常式的傳回值。 傳入訊息的標頭會被複製到新的傳出訊息中,並移除由'SpringIntegrationProperties.messageHandlerNotPropagatedHeaders' 識別的任何標頭。 預設情況下,那裡只有一個標頭設定 - contentType。 這表示會建立一個沒有設定 contentType 標頭的新傳出訊息。 這是為了確保 contentType 可以隨著實際資料的應用程式層級轉換而演變。 注意:僅當處理常式方法傳回非 Message 時,才會移除 contentType 訊息會被傳送到繫結器的輸出通道。 6. 與繫結器的輸入通道類似,繫結器的輸出通道(例如,Processor.OUTPUT)也預先配置了一個通道攔截器。 在這裡,我們會選擇性地將 contentType 標頭注入到傳出訊息中,以準備將傳出訊息的內容轉換回線路格式。 讓我們看看僅有的兩種可能情況: a. 傳出 Message 設定了 contentType 標頭。 由於標頭設定的 contentType 優先於任何其他 contentType,因此不會執行 contentType 注入,並且標頭設定的 contentType 值將在轉換回線路格式期間使用。 b. 傳出 Message 沒有設定 contentType 標頭。 繫結 contentType(預設或提供的)將作為標頭注入到傳出訊息中,並在轉換回線路格式期間使用。 7. 訊息是使用其中一個可用的 MessageConverters 轉換為線路格式。 8. 轉換後的訊息會被送回繫結器,並保留注入或現有的 contentType 標頭。 換句話說,傳出訊息將始終存在 contentType 標頭。

自訂

以上涵蓋了預設的開箱即用行為。 但這可能還不夠,所以我們是否可以自訂?如果可以,我們要如何自訂?。 2.0 中所做的內容類型協商改進的目標不僅是回答這些類型的問題,而且要確保答案是一致的 - 輸入輸出通道攔截器用來轉換為/從線路格式的 'MessageConverters' 與 'HandlerMethodArgumentResolvers' 用來轉換為/從強類型的 'MessageConverters' 相同

若要新增自訂 MessageConverter,只需建立 org.springframework.messaging.converter.MessageConverter 的實作,並將其配置為 @Bean,並將該 Bean 標註為 @StreamMessageConverter,它將作為第一個轉換器新增到現有 MessageConverters 的堆疊中,本質上優先於現有的 MessageConverters

摘要

希望到目前為止,很明顯任何和所有內容類型轉換都是由 MessageConverters 完成的。 雖然 MessageConverters 在其實作中有所不同,但大多數都利用 contentType 標頭以及目標類型 (targetClass),這使他們能夠執行類型內轉換以及與線路格式之間的轉換。 目前有一組預先配置的 MessageConverters 來支援大多數用例,因此對於大多數典型的資料類型(即,json、文字等),最終使用者實際上不需要做任何事情。 然而,值得了解現在事情如何運作以及如何自訂 - 自訂現有和/或引入新的 MessageConverter 實作

結論

我們目前正在更新文件,其中將包含更多關於此主題以及與 2.0 版本相關的其他主題的詳細資訊和範例。這些預發布部落格的主要目的是提高認知度、方便大家「嘗試」並徵求回饋意見。 也就是說;Spring Cloud Stream 2.0.0.RC1 可在此處取得

我們鼓勵您使用以下管道之一提供意見回饋

祝您使用愉快!

取得 Spring 電子報

隨時關注 Spring 電子報

訂閱

搶先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

查看全部