1. STOMP란
- 원래는 스크립트 언어(Ruby, Python, Perl 등)에서 엔터프라이즈 메시지 브로커와 통신할 수 있도록 만들어진 텍스트 기반 메시징 프로토콜.
- TCP, WebSocket 등 신뢰할 수 있는 양방향 스트리밍 프로토콜 위에서 동작 가능.
- 텍스트 지향이지만, Payload(본문) 는 텍스트 또는 바이너리 모두 지원 가능.
2. 이점
항목 | 설명 | 이점 |
@Controller를 통한 메시지 핸들링 | @MessageMapping 메소드에 메시지 자동 분배 (STOMP destination 기준) |
- WebSocketHandler 하나로 모든 메시지 처리 X
- 코드 구조가 모듈화되고 깔끔해짐 |
Spring Security를 통한 보안 설정 | 인증,권한 제어 가능 (STOMP destination + 메시지 타입 기준) |
- Destination별 접근 제어 가능
- 메시지 기반으로 권한별 분리된 보안 적용 가능 |
예시) @Controller를 통한 메시지 핸들링 가능
더보기
@Controller
public class ChatController {
// 클라이언트가 "/app/chat.send"로 메시지를 보내면 이 메소드가 호출됨
@MessageMapping("/chat.send")
@SendTo("/topic/public")
public ChatMessage sendMessage(ChatMessage message) {
// 받은 메시지를 가공해서 다시 "/topic/public"으로 브로드캐스트
return message;
}
}
예시) Spring Security로 메시지 보안 설정 가능
더보기
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(ChannelRegistration registration) {
registration.interceptors(new AuthChannelInterceptorAdapter());
}
@Override
protected boolean sameOriginDisabled() {
return true; // CORS 정책 예외 (필요에 따라)
}
}
- STOMP 메시지가 들어오는 채널을 감시
@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpDestMatchers("/app/chat/**").authenticated() // ① "/app/chat/**"로 가는 메시지는 인증 필요
.simpDestMatchers("/admin/**").hasRole("ADMIN") // ② "/admin/**"로 가는 메시지는 ADMIN 권한 필요
.anyMessage().permitAll(); // ③ 나머지는 모두 허용
}
}
- Destination별 인증/인가
3. 메시지 흐름
구성 요소
구성요소 | 설명 |
Message |
헤더 + 페이로드를 가진 기본 메시지 표현
|
MessageHandler |
메시지를 처리하는 계약 인터페이스
|
MessageChannel |
메시지를 송신할 수 있는 인터페이스 (생산자와 소비자 분리)
|
SubscribableChannel |
메시지를 구독할 수 있는 채널
|
ExecutorSubscribableChannel |
메시지를 비동기로 처리할 수 있도록 Executor를 사용하는 채널
|
메시지 흐름
내장 브로커
채널명 | 역할 | 설명 |
clientInboundChannel | 메시지 처리 (클라이언트 → 서버) | 구독 (서버: 토픽 별 세션 정보 관리) 라우팅 (SEND 메시지 🔗 @MessageMapping) |
brokerChannel | 메시지 전달 (@MessageMapping → SimpleBroker) | 메시지 Publish |
clientOutboundChannel |
메시지 전송 (SimpleBroker → 클라이언트)
|
브로드캐스팅 (SEND 메시지 ➡️ Subscriber )
- 서버 내의 토픽 별 세션으로 Subscriber 확인 |
외장 브로커
채널명 | 역할 | 설명 |
clientInboundChannel | 메시지 처리 (클라이언트 → 서버) | 구독 (서버 ➡️ 외부 브로커, 서버: 토픽 별 세션 정보 관리) 라우팅 (SEND 메시지 🔗 @MessageMapping) |
brokerChannel | 메시지 전달 (@MessageMapping → 외장 브로커) - broker relay를 통해 통신 |
메시지 Publish |
clientOutboundChannel | 메시지 전송 (외장 브로커 → 서버 → 클라이언트) - broker relay를 통해 통신 |
리스닝 (SEND 메시지 -> 벤더별 리스너 애노테이션)
브로드캐스팅 (SEND 메시지 ➡️ Subscriber) - 서버 내의 토픽 별 세션으로 Subscriber 확인 |
4. 핸들링 어노테이션
어노테이션 | 역할 | 비고 |
@MessageMapping | 클라이언트의 SEND 메시지를 특정 메서드로 연결 |
HTTP의 @RequestMapping와 유사
|
@SendTo | 메서드 결과를 특정 topic으로 브로드캐스팅 |
구독중인 모든 사용자에게 전송
|
@SendToUser | 메서드 결과를 특정 사용자에게 전송 | /user/로 라우팅됨 |
@SubscribeMapping | 클라이언트의 SUBSCRIBE 메시지를 특정 메서드와 연결 |
구독 직후 초기 데이터
|
@MessageExceptionHandler | @MessageMapping 메서드 실행 중 예외 처리 |
사용자별 에러 전송 가능
|
예제) @MessageMapping
더보기
@MessageMapping("/chat")
public void handleChatMessage(Message message) {
// 클라이언트가 /app/chat 으로 보내는 메시지를 처리
}
예제) @SendTo
더보기
@MessageMapping("/chat")
@SendTo("/topic/messages")
public Message send(Message message) {
return message;
}
예제) @SendToUser
더보기
@MessageMapping("/private-message")
@SendToUser("/queue/reply")
public Message sendPrivate(Message message) {
return message;
}
예제) @SubscribeMapping
더보기
@SubscribeMapping("/initial-data")
public InitialData sendInitialData() {
return new InitialData();
}
예제) @MessageExceptionHandler
더보기
@MessageExceptionHandler
@SendToUser("/queue/errors")
public String handleException(Throwable exception) {
return exception.getMessage();
}
출처
'Spring > Spring' 카테고리의 다른 글
[Spring WebSockets] 2-3. STOMP: 부가 기능 (1) | 2025.05.04 |
---|---|
[Spring WebSockets] WebSockets (0) | 2025.05.02 |
[Spring][AOP] 3. Advisor API (0) | 2025.04.09 |
[Spring][AOP] 2. Pointcut API (1) | 2025.04.09 |
[Spring][AOP] 1. Advice API (0) | 2025.04.09 |