(17) Spring Official Guide - Messaging with Redis

HEYDAY7·2022년 11월 2일
0

Learn Kotlin + Spring

목록 보기
18/25
post-thumbnail
post-custom-banner

Messaging with Redis

https://spring.io/guides/gs/messaging-redis/

한줄 요약

Redis를 이용하여 간단한 Pub/Sub 만들어보기

Redis 설치 및 프로젝트 구성

Redis 설치

나는 현재 윈도우 환경에서 공부를 하고 있고, 찾아본 결과 Redis에서는 윈도우 환경을 공식적으로 지원하지 않아 Microsoft에서 제공하는 library(?)를 이용하여 설치했다.
가이드에 따라 설치하고 Redis 폴더에 가서 redis-server 를 실행시켜 주면 redis-server가 켜지며 default port는 6379이다.
여기서 같은 폴더에 있는 redis-cli도 켜두자. 이는 이따 테스트에서 활용할 것이다.

프로젝트 구성

간단하다. initializer로 가서 Spring Data Redis dependency를 추가하고 프로젝트를 만들자.

코드 작업

코드는 간단하다. 대신 Spring-Redis를 활용하는 방법을 알아두기 위해 각 키워드들을 기억해 두면 좋을 것 같다.

Receiver.kt

## 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

## ~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으로 아주 많은 것들을 주입하고 있지만, 내가 봤을 때 더 간단히 쓸 수 있을 것 같아 살짝 수정했다.

receiver, listenerAdapter

기존 가이드에는 존재하는 코드이다. 이를 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를 작성해버리면 귀찮은 짓을 하지 않아도 된다. :)

@Bean template

우선 connectionFactory를 통해 Redis Server와 연결한다. 결국에는 StringRedisTemplate를 return 해주며, message를 publish 할 수 있는 template을 return 해준다.

@Bean container

RedisMessageListenerContainer를 return 해주며 connectionFactory를 통해서 Redis server와 연결한다. 핵심적인 역할은 addMessageListener를 통해 Receiver listener를 연결하여 "chat" topic에 대하여 subscribe 하는 형태로 만들어준다.

main 하위 코드

간단하게 receiver.getCount() == 0 을 통해 아직까지 메시지를 한번도 받지 못했다면~ templte을 통해 "chat" 토픽으로 "Hello from Redis!" message를 보내라~ 라는 코드이다.

Run and Test

바로 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) 구조에 대한 기본 개념을 알았으니 이게 필요한 시점에 좀 더 딮하게 파보면 될 것 같다. 유용한 가이드였다.
코드는 여기서 확인할 수 있다.

profile
(전) Junior Android Developer (현) Backend 이직 준비생
post-custom-banner

0개의 댓글