이 가이드는 Spring Data Redis를 사용하여 Redis로 전송된 메시지를 게시하고 구독하는 프로세스를 안내합니다.
개념 | 형식 |
---|---|
Receiver | POJO |
Listener | 인터페이스 구현체 |
Subscriber | 인터페이스 구현체(ActionEvent 타입 매개변수) |
Receiver
// Receiver 예시
public class ButtonReceiver {
public void onButtonClick() {
// 이벤트 발생 시 수행할 작업
}
}
Listener
// Listener 예시
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// 이벤트 발생 시 수행할 작업
}
}
Subscriber
// Subscriber 예시
public class ButtonSubscriber implements Subscriber<ActionEvent> {
@Override
public void onNext(ActionEvent event) {
// 이벤트 발생 시 수행할 작업
}
}
PoJO (Plain Old Java Object)
특정 프레임워크나 라이브러리에 종속되지 않은 단순한 자바 객체를 의미합니다. POJO는 다음과 같은 특징을 가지고 있습니다.
- 인터페이스나 추상 클래스를 상속하지 않습니다.
- 특정 프레임워크나 라이브러리에서 제공하는 특수한 메서드나 속성을 사용하지 않습니다.
- 기본 자바 클래스와 같은 방식으로 생성, 사용, 수정할 수 있습니다.
StringRedisTemplate
을 사용하여 문자열 메시지를 게시하고 MessageListenerAdapter
를 사용하여 POJO가 메시지를 구독하도록 하는 애플리케이션을 빌드합니다.
메시지를 게시하는 수단으로 Spring Data Redis를 사용하는 것이 이상하게 들릴 수도 있지만, Redis는 NoSQL 데이터 저장소뿐만 아니라 메시징 시스템도 제공합니다.
메시징 애플리케이션을 구축하기 전에 메시지 수신 및 전송을 처리할 서버를 설정해야 합니다.
Redis는 메시징 시스템과 함께 제공되는 오픈 소스 BSD 라이선스 키-값 데이터 저장소입니다. 서버는 https://redis.io/download에서 무료로 사용할 수 있습니다. 수동으로 다운로드하거나 Mac을 사용하는 경우 Homebrew를 사용하여 터미널 창에서 다음 명령을 실행하여 다운로드할 수 있습니다.
https://redis.io/docs/install/install-redis/install-redis-on-linux/
prerequisites
If you're running a very minimal distribution (such as a Docker container) you may need to install lsb-release, curl and gpg first:
sudo apt install lsb-release curl gpg
install on ubuntu
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis
redis-server
모든 메시징 기반 애플리케이션에는 메시지 게시자(Publisher)와 메시징 수신자(Reciever)가 있습니다. 메시지 수신기를 생성하려면 다음 예제(src/main/java/guides/messagingredis/Receiver.java)에 표시된 대로 메시지에 응답하는 메서드를 사용하여 수신기를 구현합니다.
데모(demonstration) 목적으로 수신자(receiver)는 수신된 메시지 수를 계산(count)합니다. 이렇게 하면 메시지를 받았을 때 신호를 보낼 수 있습니다.
package guides.messagingredis;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Receiver {
private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);
private AtomicInteger counter = new AtomicInteger();
public void receiveMessage(String message) {
LOGGER.info("Received <" + message + ">");
counter.incrementAndGet();
}
public int getCount() {
return counter.get();
}
}
Receiver
는 메시지 수신 방법을 정의하는 POJO입니다. Reciever
를 메시지 Listner
로 등록할 때 메시지 처리 방법의 이름을 원하는 대로 지정할 수 있습니다.
LoggerFactory.getLogger(클래스.class)
가 현재 클래스의 로거 인스턴스를 생성한다. 로거 인스턴스는 파일, 콘솔, 네트워크 등을 대상으로 추적하고 오류를 진단하는 역할을 한다. Spring Data Redis는 Redis로 메시지를 보내고 받는 데 필요한 모든 구성 요소를 제공합니다. 특히 다음을 구성해야 합니다.
연결 팩토리 (Connection Factory) : 템플릿과 메시지 리스너 컨테이너를 모두 구동하여 Redis 서버에 연결
메시지 리스너 컨테이너 (Message Listener Container)
Receiver
를 등록이 예제에서는 Jedis Redis 라이브러리를 기반으로 하는 JedisConnectionFactory
의 인스턴스인 Spring Boot의 기본 RedisConnectionFactory
를 사용합니다. 다음 예제(src/main/java/guides/messagingredis/MessagingRedisApplication.java)에 표시된 것처럼 연결 팩토리는 메시지 리스너 컨테이너와 Redis 템플릿 모두에 주입됩니다.
package guides.messagingredis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
@SpringBootApplication
public class MessagingRedisApplication {
private static final Logger LOGGER =
LoggerFactory.getLogger(MessagingRedisApplication.class);
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
@Bean
Receiver receiver() {
return new Receiver();
}
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
public static void main(String[] args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(MessagingRedisApplication.class, args);
StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
Receiver receiver = ctx.getBean(Receiver.class);
while (receiver.getCount() == 0) {
LOGGER.info("Sending message...");
template.convertAndSend("chat", "Hello from Redis!");
Thread.sleep(500L);
}
System.exit(0);
}
}
이 코드들은 Redis를 통해 메시지를 주고받는 과정을 담고 있어요. 여러 부분이 상호작용하며 메시지를 생성, 송수신하고 처리하는 구조입니다. 이들의 상호작용은 다음과 같습니다:
Spring Boot Application 시작
main()
메서드 실행SpringApplication.run(MessagingRedisApplication.class, args)
호출ApplicationContext
가 반환됨Spring 컨텍스트 설정
@Bean
어노테이션을 사용하여 빈을 설정하고 등록container()
, listenerAdapter()
, receiver()
, template()
메서드가 실행되어 각각의 빈이 생성되고 컨테이너에 등록됨RedisMessageListenerContainer 설정
container()
메서드가 호출되어 RedisMessageListenerContainer
빈이 생성됨setConnectionFactory()
로 Redis 연결 설정addMessageListener()
로 listenerAdapter
를 등록하고, "chat" 토픽을 구독하여 해당 토픽의 메시지를 처리할 준비를 함메시지 전송 및 수신
StringRedisTemplate
을 이용해 convertAndSend()
가 호출되어 "chat" 채널로 메시지 전송RedisMessageListenerContainer
는 등록된 리스너로부터 "chat" 토픽에 도착하는 메시지를 감지하고, MessageListenerAdapter
를 통해 수신된 메시지를 Receiver
클래스의 receiveMessage()
메서드로 라우팅함이런 과정을 통해 메시지가 생성되고 Redis를 통해 전송되며, RedisMessageListenerContainer
가 해당 토픽을 구독하여 메시지를 수신하고, 지정된 리스너를 통해 메시지를 처리하는 과정이 이뤄집니다.
while
루프:
Receiver
클래스의 getCount()
메서드는 카운터 값을 반환합니다.MessagingRedisApplication
클래스의 main()
메서드에서는 Receiver
의 인스턴스를 얻고, getCount()
를 사용하여 현재까지 받은 메시지의 수를 확인합니다.while (receiver.getCount() == 0)
구문은 받은 메시지의 수가 0인 경우에만 실행됩니다.Receiver
클래스에서 메시지를 받을 때까지 루프를 돌게끔 설계되어 있습니다.Receiver
클래스에서 메시지를 처리할 수 있도록 로직을 구성하고 있습니다.이 while
루프는 받은 메시지의 수가 0인 경우에만 실행되며, 메시지가 도착할 때까지 메시지를 기다립니다. 메시지가 도착하면 Receiver
클래스의 getCount()
가 0이 아닌 값을 반환하고 루프를 종료하게 됩니다.
main에서 ApplicationContext.getBean을 사용하는 방식은 CommandLineRunner를 이용해서도 같은 기능을 구현할 수 있다.
예시 1
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class RedisMessageProcessor implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisMessageProcessor.class);
private final Receiver receiver;
private final StringRedisTemplate template;
public RedisMessageProcessor(Receiver receiver, StringRedisTemplate template) {
this.receiver = receiver;
this.template = template;
}
@Override
public void run(String... args) throws InterruptedException {
while (receiver.getCount() == 0) {
LOGGER.info("Sending message...");
template.convertAndSend("chat", "Hello from Redis!");
Thread.sleep(500L);
}
}
}
예시 2
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@Configuration
public class CommandLineRunnerConfig {
@Autowired
private Receiver receiver;
@Autowired
private StringRedisTemplate template;
@Bean
public CommandLineRunner redisMessageProcessor() {
return args -> {
while (receiver.getCount() == 0) {
LOGGER.info("Sending message...");
template.convertAndSend("chat", "Hello from Redis!");
Thread.sleep(500L);
}
};
}
}
listenerAdapter
메서드에서 정의된 빈은 container
메서드에서 정의된 메시지 리스너 컨테이너에 메시지 리스너로 등록되어 "chat
" 토픽의 메시지를 수신합니다.
Receiver
클래스는 POJO이므로 addMessageListener()
에 필요한 MessageListener
인터페이스를 구현하는 메시지 리스너 어댑터로 래핑해야 합니다. 메시지 리스너 어댑터는 또한 메시지가 도착할 때 Receiver
클래스의 receiveMessage()
메서드를 호출하도록 구성됩니다.
메시지를 리슨하기 위해 필요한 것은 연결 팩토리와 메시지 리스너 컨테이너 빈 뿐입니다. 메시지를 보내려면 Redis 템플릿도 필요합니다. 여기에서는 키와 값 모두 String
인스턴스인 Redis의 일반적인 사용에 초점을 맞춘 RedisTemplate
구현인 StringRedisTemplate
로 구성된 빈입니다.
main()
메서드는 스프링 애플리케이션 컨텍스트를 만들면서 모든 것을 시작합니다. 애플리케이션 컨텍스트는 메시지 리스너 컨테이너를 시작하고, 메시지 리스너 컨테이너 빈은 메시지를 수신하기 시작합니다. main()
메서드는 애플리케이션 컨텍스트에서 StringRedisTemplate
빈을 검색하고 그것을 사용하여 "chat
" 토픽에 "Hello from Redis!
" 메시지를 보냅니다. 마지막으로 스프링 애플리케이션 컨텍스트를 닫고 애플리케이션이 종료됩니다.