ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • spring boot redis pub sub
    카테고리 없음 2023. 4. 20. 09:52
    Spring Boot의 redis pub sub을 알아보자. 저번에는 레디스 캐싱에 대해 알아 봤는데..약간 부족한 면이 있다 나중에 좀더 살펴 봐야 겠다. pub sub 시스템은 채널에 구독 신청을 한 모든 sub에게 메시지를 전달한다. 한마디로 구독한 채널에 대해 메시지를 전달하는 시스템을 말하는거다. Spring boot를 사용하면 좀더 쉽게 셋팅하고 구현할 수 있다. 일단 레디스가 설치 되어 있어야 한다. 레디스 설치는 인터넷에서 참고하기 바란다. 바로 소스를 보자 일단 maven으로 하기 때문에 pom xml 파일을 보자.
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.7.3</version>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    
    일단 boot의 redis를 사용하기 위해 starter-data-redis 와 json형태로 전달하기 위해 jackson을 넣어 두었다.
    public class JsonRedisTemplate<V> extends RedisTemplate<String, V> {
    
      public JsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper, Class valueType) {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        super.setKeySerializer(stringSerializer);
        super.setHashKeySerializer(stringSerializer);
        super.setHashValueSerializer(stringSerializer);
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(valueType);
        jsonRedisSerializer.setObjectMapper(objectMapper);
        super.setValueSerializer(jsonRedisSerializer);
        super.setConnectionFactory(connectionFactory);
        super.afterPropertiesSet();
      }
    }
    
    Json으로 전달을 하기 위해서 JsonRedisTemplate만들어 setValueSerializer에 json Serializer를 셋팅 하였다. 이번엔 redis에 필요한 빈 설정들을 보자
      @Bean
      RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                              MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, new PatternTopic("sendMessage"));
        container.addMessageListener(topicMessageListener(), new PatternTopic("sendMessage"));
        return container;
      }
    
      @Bean
      public TopicMessageListener topicMessageListener() {
        return new TopicMessageListener();
      }
    
      @Bean
      MessageListenerAdapter listenerAdapter(MethodMessageListener methodMessageListener) {
        return new MessageListenerAdapter(methodMessageListener, "sendMessage");
      }
    
      @Bean
      MethodMessageListener methodMessageListener() {
        return new MethodMessageListener();
      }
    
      @Autowired
      private JsonRedisTemplate jsonRedisTemplate;
    
      @Bean
      public ObjectMapper objectMapper(){
        return new ObjectMapper();
      }
    
      @Bean
      public JsonRedisTemplate jsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper){
        return new JsonRedisTemplate<>(connectionFactory,objectMapper,Object.class);
      }
    
    우리는 두가지 방법으로 설정 해보겠다. 실제 메소드를 이용해보는 방식이 하나 있고 다음은 토픽의 키 값을 이용해 보는 방식으로 해보겠다. 사실은 두개의 인터페이스는 같다. 첫번째에 있는 빈은 메시지 리스너를 등록하는 빈이다. 우리는 두가지의 방법으로 해본다고 했으니 두개를 등록 시켜놨다. 다음에 있는 TopicMessageListener 은 MessageListener 인터페이스를 구현한 구현체이다. 그 다음은 메소드 방식으로 설정 하기 위해 빈으로 등록했다. 어댑터의 첫번째 파라미터는 sub의 클래스이다. 두번째는 메소드 명으로 등록하면 된다. 그리고 아까 만든 JsonRedisTemplate을 빈으로 등록 했다. 메소드 방식의 구현체인 MethodMessageListener 소스이다.
    @Slf4j
    public class MethodMessageListener {
    
      public void sendMessage(String message) {
        log.info(message);
      }
    }
    
    
    그냥 간단하게 출력 정도만 한다. 다음으로는 토픽의 키 값으로 하는 방식이다.
    @Slf4j
    public class TopicMessageListener implements MessageListener {
    
      private RedisTemplate redisTemplate;
    
      @Autowired
      public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
      }
    
      @Override
      public void onMessage(Message message, byte[] bytes) {
        byte[] body = message.getBody();
        String str = (String) redisTemplate.getStringSerializer().deserialize(body);
        log.info("key : {}, message : {}", new String(bytes), str);
      }
    }
    
    이것또한 출력만 하는 형식으로 만들었다. 아까 본 MessageListenerAdapter 클래스도 MessageListener의 구현체로 만들어져 있다. 그럼 테스트를 해보자.
      @Autowired
      private JsonRedisTemplate jsonRedisTemplate;
    
      @Test
      public void pubsub() {
        SendMessage sendMessage = new SendMessage();
        sendMessage.setName("wonwoo");
        sendMessage.setEmail("wonwoo@test.com");
        jsonRedisTemplate.convertAndSend("sendMessage", sendMessage);
      }
    
    이렇게 테스트를 해보면 다음과 같이 로그가 남겨질 것이다.
    2016-04-23 20:32:25.050  INFO 1151 --- [    container-2] me.wonwoo.redis.MethodMessageListener    : {"name":"wonwoo","email":"wonwoo@test.com"}
    2016-04-23 20:32:25.050  INFO 1151 --- [    container-3] me.wonwoo.redis.TopicMessageListener     : key : sendMessage, message : {"name":"wonwoo","email":"wonwoo@test.com"}
    
    MethodMessageListener클래스에서 한번, TopicMessageListener 클래스에서 한번 로그가 출력 될 것이다. 이번엔 redis-cli을 실행 시켜 보자. 접속후에 다음과 같이 입력해보자
    SUBSCRIBE sendMessage
    
    그리고 테스트를 다시 돌려보면
    "{\\"name\\":\\"wonwoo\\",\\"email\\":\\"wonwoo@test.com\\"}"
    
    이런 형태의 스트링 Json이 출력 될 것이다. 이상으로 Spring의 redis pub sub를 알아 봤다! 간단하다! github에 올려 놔야겠당.

    댓글

Designed by Tistory.