RabbitMQ를 이용해 초간단 메시지 전송예제를 따라해봤습니다.
순서
1. rabbitmq 서버 실행
2. 유저 및 VirtualHost 추가
3. 프로젝트생성
4. application.yml 작성
5. RabbitMQConfig.java 작성
6. Message Sender 구현
7. Message Receiver 구현
8. 메시지 전송 테스트
환경
OS : Window
IDE : Intellij Community
JDK : 17
1. 서버 실행
윈도우에서 RabbitMQ를 설치하고 환경변수까지 설정하면 RabbitMQ가 백그라운드에서 실행되고 있을거에요.
윈도우키 눌러서 rabbitmq 검색해서 나오는 저 앱들을 통해 백그라운드 실행을 관리할 수 있습니다.
저는 일단 stop으로 백그라운드에서 실행되는걸 멈췄고,
cmd에서 rabbitmq-server를 입력해주면
#으로 나름 토끼모양...을 그리면서 실행됩니다.
http://localhost:15672/
실행하고 난 뒤에 위 주소로 들어가진다면 성공.
2. 유저 및 VHost 추가
저는 기본계정을 삭제하고 admin이라는 새로운 계정을 만들었는데,
Add a user를 통해 테스트용 계정을 하나 더 생성했습니다.
그리고 처음 생성하면 Can access virtual hosts에 아래처럼 나올텐데
Name에서 직접 계정누르고 들어가서
Set permissions 버튼 누르면
이제 virtual host에 접근할 수 있습니다.
3. 프로젝트 생성
이제 https://start.spring.io/ 에 들어가서
Dependency 를 web, devtool, RabbitMQ 세 가지만 추가하고 프로젝트를 생성해줍니다.
적당히 서버 실행 잘 되는지 확인하고
4. application.yml 작성
application.yml을 아래와 같이 작성해줍니다.
spring:
rabbitmq:
host: localhost
port: 5672
username: guestuser
password: guestuser
application:
name: HelloMessageQueue
server:
port: 8080
application name이랑 server port는 명시적으로 해줍니다
이제 기본 환경 세팅 끝!
5. RabbitMQConfig.java 작성
이제 RabbitMQConfig 파일을 작성해줄겁니다.
RabbitMQConfig 에서Bean을 4개 만들어줄건데,
- Queue queue() : Queue 인스턴스를 생성하고, Application이 사용할 큐를 정의하고 메시지를 전달하고 처리하는 기본 큐 세팅입니다.
- RabbitTemplate rabbitTemplate(ConnectionFactory ConnectionFactory) : RabbitMQ와 통신하기 위한 템플릿 인스턴스를 생성하는 역할입니다. 메시지 송수신용
- SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter)
- MessageListenerAdapter listenerAdapter(Receiver receiver) : 수신한 메시지를 특정 클래스의 특정 메서드로 전달하는 어댑터, 인자로 전달된 메서드를 자동으로 호출합니다
위 의 Bean을 모두 구현한 코드는 아래와 같습니다.
package com.example.HelloMessageQueue.step1;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
public static final String QUEUE_NAME = "helloqueue";
@Bean
public Queue queue(){
/**
* Queue 생성자로 name과 durable(Boolean) 받음
* durable : 휘발성이냐 아니냐 (volatile, persistent)
* false로 주면 휘발성 - volatile -> 서버가 종료되거나 시작될 때 큐의 메시지가 사라짐
* true로 주면 영속성 - persistent
*/
return new Queue(QUEUE_NAME, false);
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
return new RabbitTemplate(connectionFactory);
}
@Bean
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter){
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(QUEUE_NAME);
container.setMessageListener(listenerAdapter);
return container;
}
@Bean
public MessageListenerAdapter listenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
이제 각 Bean을 하나씩 살펴보면
@Bean
public Queue queue(){
/**
* Queue 생성자로 name과 durable(Boolean) 받음
* durable : 휘발성이냐 아니냐 (volatile, persistent)
* false로 주면 휘발성 - volatile -> 서버가 종료되거나 시작될 때 큐의 메시지가 사라짐
* true로 주면 영속성 - persistent
*/
return new Queue(QUEUE_NAME, false);
}
생성자의 인자로 두 가지를 받는데 첫 번째는 QUEUE_NAME, 다음은 boolean타입의 duration 입니다.큐네임은 말그대로 메시지가 쌓이고 처리될 큐의 이름을 지정하는 것이고duration은 큐가 휘발성인지, 영속성인지 여부를 정하는 옵션입니다.false로 설정하면 서버가 종료되거나 재시작 할 때 큐의 메시지가 사라집니다.
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
return new RabbitTemplate(connectionFactory);
}
JDBCTemplate과 비슷하게 RabbitMQ와 상호작용하기 위한 간단한 API를 제공합니다.
주로 메시지 전송을 담당합니다.
ConnectionFactory는 RabbitMQ와의 연결을 관리하는 객체로 rabbitTemplate에 주입하여 메시지를 전송할 때 사용할 Connection을 제공합니다.
메시지를 전송하는 Sender가 rabbitTemplate.convertAndSend() 메서드를 사용해 큐에 메시지를 넣는데 사용합니다
@Bean
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter){
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(QUEUE_NAME);
container.setMessageListener(listenerAdapter);
return container;
}
RabbitMQ 메시지를 비동기적으로 수신하기 위해 SimpleMessageListenerContainer 를 생성, 이 컨테이너가 특정 큐를 지속적으로 모니터링하고 메시지를 수신하면 지정된 리스너(MessageListenerAdapter)를 통 해 처리합니다.
ConnectionFactory는 RabbitMQ와 연결을 유지하며, 수신하는 메시지를 이 연결 을 통해 가져옵니다.
setQueueNames(QUEUE_NAME) 메서드는 특정 큐 이름을 설정. 이 컨테이너는 코드에서 설명한 큐 네임인 helloQueue에서 수신되는 메시지를 모니터링합니다.
setMessageListener(listenerAdapter)는 listenerAdapter를 설정하여, 메시지가 수신될 때 호출할 리스너를 지정합니다.
@Bean
public MessageListenerAdapter listenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "receiveMessage");
}
receiver 객체는 메시지를 처리하는 역할을 하는 Bean이며, receiveMessage 메서드 를 호출합니다.
MessageListenerAdapter는 RabbitMQ에서 수신된 메시지를 특정 메서드에 전달 할 수 있도록 해줍니다
이 경우, receiveMessage 메서드가 자동으로 호출되며, 메시지 내용을 인자로 받습니다
Receiver 클래스의 receiveMessage 메서드가 메시지를 수신하여 처리할 수 있도 록 설정합니다. (RabbitMQ에서 수신된 메시지가 receiver.receiveMessage(String message) 메서드로 전달합니다.)
6. Sender 구현
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
@Component
public class Sender { // 메시지가 전달이 됐을때 RabbitTemplate을 통해 큐에 전달하는
private final RabbitTemplate rabbitTemplate;
public Sender(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(String message){
rabbitTemplate.convertAndSend(RabbitMQConfig.QUEUE_NAME, message);
System.out.println("[#] Sent : " + message);
}
}
RabbitTemplate을 주입받고 메서드를 사용합니다.
7. Receiver 구현
import org.springframework.stereotype.Component;
@Component
public class Receiver { // Consumer 역할
public void receiveMessage(String message){
System.out.println("[#] Received : " + message);
}
}
Receiver는 Consumer 역할을 하고, 메서드 이름을 Config에서
@Bean
public MessageListenerAdapter listenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "receiveMessage");
}
어댑터에 적어준 이름과 같아야 합니다.
8. 테스트
적당하게 Controller 하나 만들어 줍니다.
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/message")
public class MessageController {
private final Sender sender;
public MessageController(Sender sender) {
this.sender = sender;
}
@PostMapping("/send")
public String sendMessage(@RequestBody String message){
sender.send(message);
return "[#] Message sent successfully " + message;
}
}
저는 postman을 이용해서 테스트 햇씁니다.
이렇게 날려보면?
이런 응답을 받았고 콘솔을 확인해보면?
잘 주고받은것 같습니다 이제 rabbitmq 모니터링 페이지에 가서 Queues and Streams 탭에 가보면
코드에서 설정한 QUEUE_NAME의 큐 이름으로 큐가 생겨있고 눌러서 들어가보면 위 화면처럼 트래픽을 확인할 수 있고
이것저것 모니터링 할 수 있습니다.
이렇게 간단하게 메시지만 주고받는 예제를 해봤습니다. 끝
'개발지식 정리' 카테고리의 다른 글
페이징 쿼리 최적화: Covering Index 활용하기 (2) | 2025.01.30 |
---|---|
비동기 아키텍처 이해 3 - Work Queues (0) | 2025.01.28 |
비동기 아키텍처 이해 1 - RabbitMQ, AMQP (0) | 2025.01.23 |