ユーザー宛先

アプリケーションは特定のユーザーを対象とするメッセージを送信でき、Spring の STOMP サポートは、この目的のために /user/ のプレフィックスが付いた宛先を認識します。例: クライアントが /user/queue/position-updates 宛先にサブスクライブする場合があります。UserDestinationMessageHandler はこの宛先を処理し、ユーザーセッションに固有の宛先(/queue/position-updates-user123 など)に変換します。これにより、一般的に名前が付けられた宛先にサブスクライブするという便利さが提供されると同時に、同じ宛先にサブスクライブする他のユーザーとの衝突が発生しないため、各ユーザーは一意の在庫ポジションの更新を受け取ることができます。

ユーザーの宛先を操作するときは、STOMP を有効にするに示すようにブローカーとアプリケーションの宛先プレフィックスを構成することが重要です。そうしないと、ブローカーは UserDestinationMessageHandler によってのみ処理される必要がある "/user" プレフィックス付きメッセージを処理します。

送信側では、/user/{username}/queue/position-updates などの宛先にメッセージを送信できます。この宛先は、UserDestinationMessageHandler によって、ユーザーに関連付けられたセッションごとに 1 つ以上の宛先に変換されます。これにより、アプリケーション内の任意のコンポーネントが、特定のユーザーをターゲットとするメッセージを送信できるようになります。名前と一般的な宛先以外の情報は必要ありません。これは、アノテーションとメッセージングテンプレートによってもサポートされます。

次の例に示すように、メッセージ処理メソッドは、@SendToUser アノテーション(共通の宛先を共有するためにクラスレベルでもサポートされています)を介して、処理中のメッセージに関連付けられたユーザーにメッセージを送信できます。

@Controller
public class PortfolioController {

	@MessageMapping("/trade")
	@SendToUser("/queue/position-updates")
	public TradeResult executeTrade(Trade trade, Principal principal) {
		// ...
		return tradeResult;
	}
}

ユーザーが複数のセッションを持っている場合、デフォルトでは、指定された宛先にサブスクライブされているすべてのセッションがターゲットになります。ただし、処理されるメッセージを送信したセッションのみをターゲットにする必要がある場合があります。これを行うには、次の例に示すように、broadcast 属性を false に設定します。

@Controller
public class MyController {

	@MessageMapping("/action")
	public void handleAction() throws Exception{
		// raise MyBusinessException here
	}

	@MessageExceptionHandler
	@SendToUser(destinations="/queue/errors", broadcast=false)
	public ApplicationError handleException(MyBusinessException exception) {
		// ...
		return appError;
	}
}
一般に、ユーザーの宛先は認証されたユーザーを意味しますが、厳密には必須ではありません。認証されたユーザーに関連付けられていない WebSocket セッションは、ユーザー宛先にサブスクライブできます。このような場合、@SendToUser アノテーションは broadcast=false とまったく同じように動作します(つまり、処理中のメッセージを送信したセッションのみを対象とします)。

たとえば、Java 構成または XML 名前空間によって作成された SimpMessagingTemplate を挿入することにより、任意のアプリケーションコンポーネントからユーザーの宛先にメッセージを送信できます。(@Qualifier での修飾に必要な場合、Bean 名は brokerMessagingTemplate です)次の例は、その方法を示しています。

@Service
public class TradeServiceImpl implements TradeService {

	private final SimpMessagingTemplate messagingTemplate;

	@Autowired
	public TradeServiceImpl(SimpMessagingTemplate messagingTemplate) {
		this.messagingTemplate = messagingTemplate;
	}

	// ...

	public void afterTradeExecuted(Trade trade) {
		this.messagingTemplate.convertAndSendToUser(
				trade.getUserName(), "/queue/position-updates", trade.getResult());
	}
}
外部メッセージブローカーでユーザー宛先を使用する場合は、非アクティブなキューを管理する方法についてブローカーのドキュメントを確認して、ユーザーセッションが終了するとすべての一意のユーザーキューが削除されるようにする必要があります。例: /exchange/amq.direct/position-updates などの宛先を使用すると、RabbitMQ は自動削除キューを作成します。その場合、クライアントは /user/exchange/amq.direct/position-updates をサブスクライブできます。同様に、ActiveMQ には非アクティブな宛先をパージするための構成オプションがあります [Apache] (英語)

マルチアプリケーションサーバーのシナリオでは、ユーザーが別のサーバーに接続しているため、ユーザーの宛先が未解決のままになることがあります。このような場合、未解決のメッセージをブロードキャストするように宛先を構成して、他のサーバーが試行できるようにすることができます。これは、Java 構成の MessageBrokerRegistry の userDestinationBroadcast プロパティおよび XML の message-broker エレメントの user-destination-broadcast 属性を介して実行できます。