訊息流
一旦 STOMP 端點暴露,Spring 應用程式就成為連線客戶端的 STOMP 代理。本節描述了伺服器端的訊息流。
spring-messaging 模組包含對訊息應用程式的基礎支援,這些支援起源於 Spring Integration,後來被提取並整合到 Spring Framework 中,以便在許多 Spring 專案和應用程式場景中廣泛使用。以下列表簡要描述了一些可用的訊息抽象。
-
Message:訊息的簡單表示,包括頭部和有效載荷。
-
MessageHandler:處理訊息的契約。
-
MessageChannel:用於傳送訊息的契約,實現了生產者和消費者之間的鬆散耦合。
-
SubscribableChannel:帶有
MessageHandler訂閱者的MessageChannel。 -
ExecutorSubscribableChannel:使用
Executor傳遞訊息的SubscribableChannel。
Java 配置(即 @EnableWebSocketMessageBroker)和 XML 名稱空間配置(即 <websocket:message-broker>)都使用上述元件來組裝訊息工作流。以下圖表顯示了啟用簡單內建訊息代理時使用的元件。
上圖顯示了三個訊息通道:
-
clientInboundChannel:用於傳遞從 WebSocket 客戶端接收到的訊息。 -
clientOutboundChannel:用於向 WebSocket 客戶端傳送伺服器訊息。 -
brokerChannel:用於從伺服器端應用程式程式碼中向訊息代理傳送訊息。
下圖顯示了當配置外部代理(例如 RabbitMQ)來管理訂閱和廣播訊息時使用的元件。
前兩張圖的主要區別在於,“代理中繼”用於透過 TCP 將訊息傳遞給外部 STOMP 代理,並從代理向下傳遞訊息給訂閱的客戶端。
當從 WebSocket 連線接收到訊息時,它們被解碼為 STOMP 幀,轉換為 Spring Message 表示,併發送到 clientInboundChannel 進行進一步處理。例如,目標頭部以 /app 開頭的 STOMP 訊息可能會路由到註解控制器中的 @MessageMapping 方法,而 /topic 和 /queue 訊息可能會直接路由到訊息代理。
處理來自客戶端的 STOMP 訊息的註解 @Controller 可以透過 brokerChannel 向訊息代理傳送訊息,代理會透過 clientOutboundChannel 將訊息廣播給匹配的訂閱者。同樣的控制器也可以響應 HTTP 請求執行相同的操作,因此客戶端可以執行 HTTP POST,然後 @PostMapping 方法可以向訊息代理傳送訊息以廣播給訂閱的客戶端。
我們可以透過一個簡單的示例來追溯訊息流。考慮以下示例,它設定了一個伺服器:
-
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())
}
}
上述示例支援以下訊息流:
-
客戶端連線到
localhost:8080/portfolio,一旦 WebSocket 連線建立,STOMP 幀開始在其上傳輸。 -
客戶端傳送一個 SUBSCRIBE 幀,其目標頭部為
/topic/greeting。收到並解碼後,訊息被髮送到clientInboundChannel,然後路由到訊息代理,訊息代理儲存客戶端訂閱。 -
客戶端傳送一個 SEND 幀到
/app/greeting。/app字首有助於將其路由到註解控制器。剝離/app字首後,目標的其餘部分/greeting會對映到GreetingController中的@MessageMapping方法。 -
從
GreetingController返回的值被轉換為一個 SpringMessage,其有效載荷基於返回值,預設目標頭部為/topic/greeting(從輸入目標派生,其中/app被/topic替換)。生成的訊息被髮送到brokerChannel並由訊息代理處理。 -
訊息代理找到所有匹配的訂閱者,並透過
clientOutboundChannel向每個訂閱者傳送一個 MESSAGE 幀,訊息從那裡被編碼為 STOMP 幀並在 WebSocket 連線上傳輸。
下一節將提供有關注解方法的更多詳細資訊,包括支援的引數型別和返回值。