訊息流程

一旦 STOMP 端點被公開,Spring 應用程式就會成為連線用戶端的 STOMP Broker。本節描述伺服器端的訊息流程。

spring-messaging 模組包含對訊息應用程式的基礎支援,這些支援源自於 Spring Integration,後來被提取並整合到 Spring 框架中,以便在許多 Spring 專案和應用場景中更廣泛地使用。以下列表簡要描述了一些可用的訊息抽象概念

Java 組態(即 @EnableWebSocketMessageBroker)和 XML Namespace 組態(即 <websocket:message-broker>)都使用上述組件來組裝訊息工作流程。以下圖表顯示啟用簡單內建訊息 Broker 時使用的組件

message flow simple broker

上圖顯示了三個訊息通道

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

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

  • brokerChannel:用於從伺服器端應用程式程式碼將訊息傳送到訊息 Broker。

下圖顯示了組態外部 Broker(例如 RabbitMQ)以管理訂閱和廣播訊息時使用的組件

message flow broker relay

前兩個圖表之間的主要區別在於使用「Broker Relay」透過 TCP 將訊息傳遞到外部 STOMP Broker,以及將訊息從 Broker 傳遞到已訂閱的用戶端。

當從 WebSocket 連線接收到訊息時,它們會被解碼為 STOMP Frame,轉換為 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 Frame 就開始在其上流動。

  2. 用戶端傳送具有 /topic/greeting 目的地標頭的 SUBSCRIBE Frame。一旦接收和解碼,訊息就會傳送到 clientInboundChannel,然後路由到訊息 Broker,訊息 Broker 會儲存用戶端訂閱。

  3. 用戶端傳送 SEND Frame 到 /app/greeting/app 前綴有助於將其路由到註解控制器。在剝離 /app 前綴後,目的地的剩餘 /greeting 部分會對應到 GreetingController 中的 @MessageMapping 方法。

  4. GreetingController 傳回的值會轉換為 Spring Message,其 Payload 基於傳回值,預設目的地標頭為 /topic/greeting(從輸入目的地衍生,其中 /app/topic 取代)。產生的訊息會傳送到 brokerChannel 並由訊息 Broker 處理。

  5. 訊息 Broker 找到所有相符的訂閱者,並透過 clientOutboundChannel 將 MESSAGE Frame 傳送給每個訂閱者,訊息從那裡被編碼為 STOMP Frame 並在 WebSocket 連線上傳送。

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