๐ŸŒ Infra

[MQ] Springboot STOMP ํ”„๋กœํ† ์ฝœ์œผ๋กœ Web Socket ํ†ต์‹ ํ•˜๊ธฐ

jcowwk 2025. 1. 12. 22:22

Springboot STOMP ํ”„๋กœํ† ์ฝœ์œผ๋กœ Web Socket ํ†ต์‹ ํ•˜๊ธฐ


1. ๋ฉ”์‹œ์ง€ ํ(Message Queue)

2. STOMP ํ”„๋กœํ† ์ฝœ

3. Springboot STOMP ํ”„๋กœํ† ์ฝœ์œผ๋กœ Web Socket ํ†ต์‹ ํ•˜๊ธฐ


1. ๋ฉ”์‹œ์ง€ ํ(Message Queue)

๋ฉ”์‹œ์ง€ ํ(Message Queue)๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐ„์˜ ํ†ต์‹ ์„ ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ฉ”์‹œ์ง€๋ฅผ ํ(Queue)์— ์ž„์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜์—ฌ, FIFO(First-In-First-Out, ์„ ์ž…์„ ์ถœ)๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๋ฉ”์‹œ์ง€ ํ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” RabbitMQ, Kafka์™€ ๊ฐ™์€ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค(Message Broker)๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ํฌ์ŠคํŒ…์—์„œ๋Š” RabbitMQ์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

2. STOMP ํ”„๋กœํ† ์ฝœ

STOMP(Simple Text Oriented Messaging Protocol)์€ ๋ฉ”์„ธ์ง€๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ „๋‹ฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค.

TCP์™€ WebSocket ๊ฐ™์€ ์–‘๋ฐฉํ–ฅ ํ†ต์‹  ํ”„๋กœํ† ์ฝœ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

3. Springboot STOMP ํ”„๋กœํ† ์ฝœ์œผ๋กœ Web Socket ํ†ต์‹ ํ•˜๊ธฐ

Springboot์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‚ด์žฅ SimpleBroker๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. STOMP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด์žฅ SimpleBroker์™€ ํ†ต์‹ ํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. RabbitMQ์™€ ๊ฐ™์€ ์™ธ๋ถ€ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค์˜ ์—ฐ๋™ํ•  ๋•Œ ํ†ต์‹ ์„ ์œ„ํ•ด STOMP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ํ™œ์šฉํ•œ ํ†ต์‹  ๋ฐฉ์‹์— ๋Œ€ํ•ด ํ•™์Šตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ „์ฒด์ ์ธ ํ†ต์‹  ๊ตฌํ˜„์„ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜์˜ 6๊ฐœ์˜ ํŒŒ์ผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

WebSocketConfig.java, GreetingController.java, Greeting.java, HelloMessage.java, index.html, app.js 

 

ํ•ด๋‹น ํฌ์ŠคํŒ…์—์„œ๋Š” 4๊ฐœ์˜ javaํŒŒ์ผ์— ๋Œ€ํ•œ ์„ค๋ช…๋งŒ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

- WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setApplicationDestinationPrefixes("/app");
  }

  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/gs-guide-websocket");
  }
}

 

configureMessageBroker๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ฒฝ๋กœ๋ฅผ ์„ค์ •

registerStompEndPoints๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ์ž…๊ตฌ ์„ค์ •

 

1. configureMessageBroker ๋ฉ”์„œ๋“œ - 1๋ฒˆ ๋ฌธ์žฅ

/topic์€ ๋ชจ๋“  ๋ฉ”์‹œ์ง€๋Š” /topic ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

/topic/greetings ์ด๋ผ๋Š” ๊ฒฝ๋กœ๊ฐ€ ์žˆ์œผ๋ฉด ์ด ๊ฒฝ๋กœ๋ฅผ ๊ตฌ๋…ํ•œ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋ฉ”์‹œ์ง€๊ฐ€ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

 

2. configureMessageBroker ๋ฉ”์„œ๋“œ - 2๋ฒˆ ๋ฌธ์žฅ

/app์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ /app/hello ๊ฐ™์€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„๋กœ ๊ฐ€๋Š” ๋ฉ”์‹œ์ง€์˜ ์ถœ๋ฐœ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.

 

 

3. registerStompEndPoints ๋ฉ”์„œ๋“œ

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ์ฃผ์†Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ๋Š” http://[์„œ๋ฒ„์ฃผ์†Œ]/gs-guide-websocket ์œผ๋กœ ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

- GreetingController.java

@Controller
public class GreetingController {

  @MessageMapping("/hello")
  @SendTo("/topic/greetings")
  public Greeting greeting(HelloMessage message) throws Exception {
    Thread.sleep(1000);
    return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
  }
}

 

1. @MessageMapping("/hello")

ํด๋ผ์ด์–ธํŠธ๊ฐ€ /app/hello ๊ฒฝ๋กœ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋ฉด ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

 

2. @SendTo("/topic/greetings")

๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๊ฐ€ /topic/greetings ๊ฒฝ๋กœ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

 

3. Thread.sleep(1000);

1์ดˆ๋™์•ˆ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„๊ฐ€ ๊ณ„์‚ฐ์„ ํ•˜๊ฑฐ๋‚˜ ์‘๋‹ต์„ ์ž ์‹œ ์ง€์—ฐ์‹œํ‚ค๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

4. return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");

message.getName()์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์•…์˜์ ์ธ HTML ์ฝ”๋“œ ์‚ฝ์ž… ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด HtmlUtils.htmlEscape๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ Greeting ๊ฐ์ฒด๋Š” /topic/greetings ๊ฒฝ๋กœ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

 

- Greeting.java

public class Greeting {

  private String content;

  public Greeting() {
  }

  public Greeting(String content) {
    this.content = content;
  }

  public String getContent() {
    return content;
  }
}

 

/topic/greetings ๊ฒฝ๋กœ๋กœ ์ „๋‹ฌ๋  Greeting ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

- HelloMessage.java

public class HelloMessage {

  private String name;

  public HelloMessage() {
  }

  public HelloMessage(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

 

ํด๋ผ์ด์–ธํŠธ์—์„œ html๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ฌ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.


์ฐธ๊ณ  ์‚ฌ์ดํŠธ

 

[๊ฐ„๋‹จ์ •๋ฆฌ] ๋ฉ”์„ธ์ง€ ํ(Message Queue)๋ž€?

๊ฐœ์š”๋ฉ”์‹œ์ง€ ํ(Message Queue)๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์†ก์‹ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Producer)๊ณผ ์ด๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Consumer) ๊ฐ„์˜ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€ ํ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์‹œ์ง€๋ฅผ

hahahoho5915.tistory.com

 

 

[์„œ๋ฒ„] ๋ฉ”์„ธ์ง€ ํ(Message Queue) ์„ ์•Œ์•„๋ณด์ž

์•ˆ๋…•ํ•˜์„ธ์š” ์˜ค๋Š˜์€ ๋ฉ”์„ธ์ง€ ํ(Message Queue) ์— ๋Œ€ํ•ด ์ „๋ฐ˜์ ์ธ ์ดํ•ด์™€ ๋Œ€ํ‘œ์ ์ธ ์ข…๋ฅ˜์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.๋ฉ”์„ธ์ง€ ํ ๋ฅผ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์•Œ์•„๋ณด๊ธฐ ์ „์— ๋ฉ”์„ธ์ง€ ์ง€ํ–ฅ ๋ฏธ๋“ค์›จ์–ด(MOM) ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

velog.io

 

 

[IT์ •๋ณด] ๋ฉ”์‹œ์ง€ ํ(Message Queue, MQ) ๊ฐœ๋…

๋ฉ”์‹œ์ง€ ํ(Message Queue, MQ)๋ž€? ๋ฉ”์‹œ์ง€ ํ(MessageQueue: MQ)๋Š” ํ”„๋กœ์„ธ์Šค ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ ์ธ์Šคํ„ด...

blog.naver.com

 

 

[RabbitMQ] ๊ธฐ์ดˆ ๊ฐœ๋…

AMQP๋ฅผ ๊ตฌํ˜„ํ•œ ์˜คํ”ˆ์†Œ์Šค ๋ฉ”์„ธ์ง€ ๋ธŒ๋กœ์ปค์ด๋‹ค.producers์—์„œ consumers๋กœ ๋ฉ”์„ธ์ง€(์š”์ฒญ)๋ฅผ ์ „๋‹ฌํ•  ๋•Œ ์ค‘๊ฐ„์—์„œ ๋ธŒ๋กœ์ปค ์—ญํ• ์„ ํ•œ๋‹ค.์‚ฌ์šฉํ•˜๋Š” ์ผ€์ด์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.์š”์ฒญ์„ ๋งŽ์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•  ๋•Œ์š”์ฒญ

velog.io

 

 

[Architecture] ๋ฉ”์‹œ์ง€ ํ์™€ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค - MSA์˜ ํ•ต์‹ฌ์š”์†Œ

๋ฉ”์‹œ์ง€ ํ์˜ ์ •์˜์™€ MSA ์•„ํ‚คํ…์ฒ˜์—์„œ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค๊ฐ€ ์™œ ํ•„์š”ํ•œ์ง€ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

velog.io

 

 

WebSocket์˜ Stomp

Websocket์€ ๋ฉ”์‹œ์ง• ๋ฐฉ์‹๋งŒ ์ž˜ ์ •์˜ํ•œ๋‹ค๋ฉด ์ข‹์€ Server/Client ์†Œ์ผ“ ์„œ๋ฒ„๋ฅผ ์™„์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.ํ•˜์ง€๋งŒ, ๋‹จ์ˆœํ•œ ํ†ต์‹  ๊ตฌ์กฐ๋กœ ์ธํ•ด WebSocket๋งŒ์„ ์ด์šฉํ•ด ์†Œ์ผ“์„œ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ํ•ด๋‹น ๋ฉ”์„ธ์ง€๊ฐ€ ์–ด๋–ค ์š”์ฒญ์ธ์ง€, ์–ด

velog.io

 

 

Spring Websocket & STOMP

์˜ค๋žซ๋งŒ์— ์ž‘์„ฑํ•˜๋Š” ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ…์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ ๊ธฐ๋ฐ˜์˜ ์›น์†Œ์ผ“ ๋ฐ STOMP์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์„ ์ฝ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ธฐ๋ณธ์ ์ธ HTTP ์ง€์‹์ด ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œ

brunch.co.kr

 

 

Getting Started | Using WebSocket to build an interactive web application

In Spring’s approach to working with STOMP messaging, STOMP messages can be routed to @Controller classes. For example, the GreetingController (from src/main/java/com/example/messagingstompwebsocket/GreetingController.java) is mapped to handle messages t

spring.io

 

๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉด ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์„ธ์š” !

ํ”ผ๋“œ๋ฐฑ์€ ์–ธ์ œ๋‚˜ ํ™˜์˜์ž…๋‹ˆ๋‹ค <3