訊息流

一旦暴露 STOMP 端點,Spring 應用程式就成為連線客戶端的 STOMP broker。本節描述了伺服器端的訊息流。

spring-messaging 模組包含訊息應用程式的基礎支援,它起源於 Spring Integration,後來被提取並納入 Spring Framework 中,以便在許多 Spring 專案和應用程式場景中更廣泛地使用。以下列表簡要描述了一些可用的訊息抽象

Java 配置(即 @EnableWebSocketMessageBroker)和 XML 名稱空間配置(即 <websocket:message-broker>)都使用上述元件來組裝訊息工作流。下圖顯示了啟用簡單內建訊息 broker 時使用的元件

message flow simple broker

上圖顯示了三個訊息通道

  • clientInboundChannel:用於傳遞從 WebSocket 客戶端接收的訊息。

  • clientOutboundChannel:用於向 WebSocket 客戶端傳送伺服器訊息。

  • brokerChannel:用於在伺服器端應用程式程式碼中向訊息 broker 傳送訊息。

下圖顯示了配置外部 broker(例如 RabbitMQ)用於管理訂閱和廣播訊息時使用的元件

message flow broker relay

前兩個圖的主要區別在於使用“broker 中繼”透過 TCP 將訊息傳遞到外部 STOMP broker,以及將訊息從 broker 傳遞給訂閱的客戶端。

當從 WebSocket 連線接收到訊息時,它們被解碼為 STOMP 幀,轉換為 Spring Message 表示形式,併發送到 clientInboundChannel 進行進一步處理。例如,目的地頭部以 /app 開頭的 STOMP 訊息可以路由到註解控制器的 @MessageMapping 方法,而 /topic/queue 訊息可以直接路由到訊息 broker。

處理來自客戶端的 STOMP 訊息的註解 @Controller 可以透過 brokerChannel 向訊息 broker 傳送訊息,然後 broker 透過 clientOutboundChannel 將訊息廣播給匹配的訂閱者。同一個控制器也可以響應 HTTP 請求執行相同的操作,因此客戶端可以執行 HTTP POST,然後 @PostMapping 方法可以將訊息傳送到訊息 broker,以廣播給訂閱的客戶端。

我們可以透過一個簡單的示例來追蹤流程。考慮以下示例,它設定了一個伺服器

  • Java

  • Kotlin

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/portfolio");
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.setApplicationDestinationPrefixes("/app");
		registry.enableSimpleBroker("/topic");
	}
}
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfiguration : WebSocketMessageBrokerConfigurer {
	override fun registerStompEndpoints(registry: StompEndpointRegistry) {
		registry.addEndpoint("/portfolio")
	}

	override fun configureMessageBroker(registry: MessageBrokerRegistry) {
		registry.setApplicationDestinationPrefixes("/app")
		registry.enableSimpleBroker("/topic")
	}
}
  • Java

  • Kotlin

@Controller
public class GreetingController {

	@MessageMapping("/greeting")
	public String handle(String greeting) {
		return "[" + getTimestamp() + ": " + greeting;
	}

	private String getTimestamp() {
		return new SimpleDateFormat("MM/dd/yyyy h:mm:ss a").format(new Date());
	}

}
@Controller
class GreetingController {
	
	@MessageMapping("/greeting")
	fun handle(greeting: String): String {
		return "[${getTimestamp()}: $greeting"
	}

	private fun getTimestamp(): String {
		return SimpleDateFormat("MM/dd/yyyy h:mm:ss a").format(Date())
	}
}

上例支援以下流程

  1. 客戶端連線到 localhost:8080/portfolio,一旦建立 WebSocket 連線,STOMP 幀就開始在其上傳輸。

  2. 客戶端傳送一個 SUBSCRIBE 幀,其目的地頭部為 /topic/greeting。收到並解碼後,訊息傳送到 clientInboundChannel,然後路由到訊息 broker,由其儲存客戶端訂閱資訊。

  3. 客戶端向 /app/greeting 傳送一個 SEND 幀。/app 字首有助於將其路由到註解控制器。移除 /app 字首後,目的地剩餘的 /greeting 部分對映到 GreetingController 中的 @MessageMapping 方法。

  4. GreetingController 返回的值被轉換為一個 Spring Message,其載荷基於返回值,預設目的地頭部為 /topic/greeting(從輸入目的地中將 /app 替換為 /topic 派生而來)。生成的訊息被髮送到 brokerChannel 並由訊息 broker 處理。

  5. 訊息 broker 查詢所有匹配的訂閱者,並透過 clientOutboundChannel 向每個訂閱者傳送一個 MESSAGE 幀,訊息從 clientOutboundChannel 被編碼為 STOMP 幀並在 WebSocket 連線上傳輸。

下一節將提供更多關於註解方法的詳細資訊,包括支援的引數型別和返回值。