https://spring.io/guides/gs/messaging-redis/
Redis를 이용하여 간단한 Pub/Sub 만들어보기
나는 현재 윈도우 환경에서 공부를 하고 있고, 찾아본 결과 Redis에서는 윈도우 환경을 공식적으로 지원하지 않아 Microsoft에서 제공하는 library(?)를 이용하여 설치했다.
가이드에 따라 설치하고 Redis 폴더에 가서 redis-server 를 실행시켜 주면 redis-server가 켜지며 default port는 6379이다.
여기서 같은 폴더에 있는 redis-cli도 켜두자. 이는 이따 테스트에서 활용할 것이다.
간단하다. initializer로 가서 Spring Data Redis dependency를 추가하고 프로젝트를 만들자.
코드는 간단하다. 대신 Spring-Redis를 활용하는 방법을 알아두기 위해 각 키워드들을 기억해 두면 좋을 것 같다.
## Receiver.kt
@Component
class Receiver: MessageListener {
private val logger: Logger = LoggerFactory.getLogger(Receiver::class.java)
private val counter = AtomicInteger()
override fun onMessage(message: Message, pattern: ByteArray?) {
logger.info("Received <$message> by onMessage")
counter.incrementAndGet()
}
fun getCount(): Int {
return counter.get()
}
}
기존 가이드 코드와 살짝 다른 것을 볼 수 있다. MessageListener 상속받아 onMessage method를 override 해서 작성해주었다. 동작은 원래와 유사하다고 보면 되고, 상세한 설명은 아래에서 볼 수 있다.
## ~Application.kt
@SpringBootApplication
class MessagingWithRedisApplication {
@Bean
fun container(
connectionFactory: RedisConnectionFactory,
receiver: Receiver
): RedisMessageListenerContainer {
val container = RedisMessageListenerContainer()
container.setConnectionFactory(connectionFactory)
container.addMessageListener(receiver, PatternTopic("chat"))
return container
}
@Bean
fun template(connectionFactory: RedisConnectionFactory): StringRedisTemplate {
return StringRedisTemplate(connectionFactory)
}
}
fun main(args: Array<String>) {
val logger: Logger = LoggerFactory.getLogger("main")
val ctx = runApplication<MessagingWithRedisApplication>(*args)
val template = ctx.getBean(StringRedisTemplate::class.java)
val receiver = ctx.getBean(Receiver::class.java)
while (receiver.getCount() == 0) {
logger.info("Sending message...")
template.convertAndSend("chat", "Hello from Redis!")
Thread.sleep(500L)
}
exitProcess(0)
}
가이드를 보면 @Bean으로 아주 많은 것들을 주입하고 있지만, 내가 봤을 때 더 간단히 쓸 수 있을 것 같아 살짝 수정했다.
기존 가이드에는 존재하는 코드이다. 이를 kotlin으로 옮겨 적으면 아래와 같이 생겼었다.
@Bean
fun listenerAdapter(receiver: Receiver): MessageListenerAdapter {
return MessageListenerAdapter(receiver, "receiveMessage")
}
@Bean
fun receiver(): Receiver {
return Receiver()
}
receiver()의 경우 앞서 정의한 Receiver를 주입해주는 코드이며, listenerAdapter는 그런 receiver를 받아 "Receiver의 receiveMessage method로 message가 왔을 때 처리해주세요~" 라고 말하는 ListenerAdapter를 만드는 것이다.
여기서 우선 receiver()의 경우 Receiver.kt를 작성할 때 @Component annotation을 붙혀주는 것으로 제거할 수 있다. 또한 가이드를 잘 읽어보면 MessageListenerAdapter를 사용하는 이유는 Receiver 가 POJO 이기 때문이라고 하는데, 이 Receiver class 자체를 MessageListener를 상속받게 만들어 onMessage method를 작성해버리면 귀찮은 짓을 하지 않아도 된다. :)
우선 connectionFactory를 통해 Redis Server와 연결한다. 결국에는 StringRedisTemplate를 return 해주며, message를 publish 할 수 있는 template을 return 해준다.
RedisMessageListenerContainer를 return 해주며 connectionFactory를 통해서 Redis server와 연결한다. 핵심적인 역할은 addMessageListener를 통해 Receiver listener를 연결하여 "chat" topic에 대하여 subscribe 하는 형태로 만들어준다.
간단하게 receiver.getCount() == 0 을 통해 아직까지 메시지를 한번도 받지 못했다면~ templte을 통해 "chat" 토픽으로 "Hello from Redis!" message를 보내라~ 라는 코드이다.
바로 application.kt를 실행하기 전에! 아까 켜뒀던 redis-cli로 가보자. 그리고 아래 사진과 같이 subscribe chat을 쳐주자. 그러면 해당 cli 또한 chat topic을 subscribe 하고 있는 상태가 된다.
그러고서 이제 application.kt를 실행해 주면 이런 결과를 얻을 수 있다. 아래와 같이 redis-cli에는 redis 서버에 chat 토픽으로 쐈던 메시지가 그대로 출력되고 있는 것을 볼 수 있다.
또, ide에서 run 탭을 보면 우리가 설정해둔 receiver가 정상적으로 동작해서 "Received <Hello from Redis!> by onMessage"를 출력한 것을 볼 수 있다.
Redis를 직접 써보기는 거의 처음이지만, messaging 서버로의 기본 동작에 대해 잘 알아본 것 같다. Publisher와 Subscriber(Receiver) 구조에 대한 기본 개념을 알았으니 이게 필요한 시점에 좀 더 딮하게 파보면 될 것 같다. 유용한 가이드였다.
코드는 여기서 확인할 수 있다.