스프링부트 Redis 연습 2 - pub/sub 구현

TreeSick·2022년 2월 15일
3

레디스

목록 보기
2/3

1편에서는 redis를 이용한 기본적인 get/set 구현을 했습니다.

https://velog.io/@rainbowweb/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-Redis-%EC%97%B0%EC%8A%B5-1

이번에는 redis를 pub/sub 메시징으로 사용해보겠습니다!

기본적으로, Redis Pub/Sub의 경우 메시지 지속성, 즉 메시지를 전송한 후에 어디에도 저장이 되지 않는다는 점이 있습니다!(kafka와 다르게)

Redis 기본 이론

깃헙에 있는 정리본을 참고해주세요!

https://github.com/namusik/TIL-SampleProject/tree/main/Redis

Redis window 설치 및 실행

https://oingdaddy.tistory.com/225

Redis 서버를 킨 상태에서 코드를 작성해봅시다!

소스코드

https://github.com/namusik/TIL-SampleProject/tree/main/Redis/Redis%20pub-sub%20%EC%98%88%EC%A0%9C

작업환경

IntelliJ
Spring-boot
java 11
gradle

dependency

Lombok
spring web
spring data redis

application.yml

spring:
  redis:
    host: localhost
    port: 6379
    

ChatMessage Model

@Getter
@NoArgsConstructor
@AllArgsConstructor

public class ChatMessage {
    private String sender;
    private String context;
}

메세지 모델 클래스
보내는사람과 내용을 필드로 가지고 있음.

RedisConfig

@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }
    
    //redisTemplate 설정
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(ChatMessage.class));
        return redisTemplate;
    }
    
    //리스너어댑터 설정
    @Bean
    MessageListenerAdapter messageListenerAdapter() {
        return new MessageListenerAdapter(new RedisSubService());
    }
    
    //컨테이너 설정
    @Bean
    RedisMessageListenerContainer redisContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory());
        container.addMessageListener(messageListenerAdapter(), topic());
        return container;
    }

    //pub/sub 토픽 설정
    @Bean
    ChannelTopic topic() {
        return new ChannelTopic("topic1");
    }
}
  1. topic() : redis에서 pub/sub할 채널을 지정해줌.

  2. MessageListenerAdapter : 스프링에서 비동기 메시지를 지원하는 마지막 컴포넌트.
    정해진 채널로 들어온 메시지를 처리할 action을 정의.

  3. MessageListenerContainer : JMS template과 함께 스프링에서 JMS메시징을 사용하는 핵심 컴포넌트. MDP(message-driven POJO)를 사용하여 비동기 메시지를 받는데 사용. 메시지의 수신관점에서 볼 떄 필요
    MessageListener를 생성하는데 사용

RedisSubService

@Service
@RequiredArgsConstructor
public class RedisSubService implements MessageListener {
    public static List<String> messageList = new ArrayList<>();
    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void onMessage(Message message, byte[] pattern) {
        try {
            ChatMessage chatMessage = mapper.readValue(message.getBody(), ChatMessage.class);
            messageList.add(message.toString());

            System.out.println("받은 메시지 = " + message.toString());
            System.out.println("chatMessage.getSender() = " + chatMessage.getSender());
            System.out.println("chatMessage.getContext() = " + chatMessage.getContext());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

MessageListener를 구현한 서비스 클래스

ObjectMaper.readValue를 사용해서 JSON을 파싱해서 자바 객체(ChatMessage.Class)로 바꿔준다

Redis에는 메시지가 저장되지 않아서 List에 추가해주고 출력하는 형태. DB 연결로 바꾸는 것도 좋음.

onMessage() 메서드는 메시지를 subscribe했을 때 수행할 메서드

RedisPubService

@Service
@RequiredArgsConstructor
public class RedisPubService {
    private final RedisTemplate<String, Object> redisTemplate;

    public void sendMessage(ChatMessage chatMessage) {
        redisTemplate.convertAndSend("topic1", chatMessage);

    }
}

해당 채널로 메시지를 Pub하는 Service

Config에서 설정해준 redisTemplate.converAndSend()메서드를 사용.

RedisController

@RestController
@RequiredArgsConstructor
public class RedisController {
    private final RedisPubService redisPubService;

    @PostMapping("api/chat")
    public String pubSub(@RequestBody ChatMessage chatMessage) {
        //메시지 보내기
        redisPubService.sendMessage(chatMessage);

        return "success";
    }
}

보내려는 ChatMessage를 pubservice를 통해 publish하면 SubService가 해당 채널을 구독하고 있기 때문에 채팅 내용이 출려됨.

실행결과

Postman을 사용해서 api를 실행시키면

성공시 "success"를 반환하고

publish한 ChatMessage의 sender와 context가 제대로 출력되면 성공

참고

https://jeong-pro.tistory.com/175
https://brunch.co.kr/@springboot/374
https://starplatina.tistory.com/374
https://blog.outsider.ne.kr/985

profile
깃헙에 올린 예제 코드의 설명을 적어놓는 블로그

1개의 댓글

comment-user-thumbnail
2023년 7월 26일

깔끔하네요. 잘 보고 갑니다.

답글 달기