본문 바로가기

IT

[Spring Boot] 스프링 클라우드 (Spring Cloud) (+ RabbitMQ 연결)

업무에서 RabbitMQ 를 사용하게 되면서 Spring Boot에도 RabbitMQ 를 적용해보고싶었다. 적용하면서 사용한 스프링 클라우드에 대해 정리하고 작성한 코드를 공유하려고 한다.

 

스프링 클라우드란?

개발자가 분산 시스템에서 사용되는 패턴을 빠르게 구축할 수 있도록 도와주는 도구이다. (라이브러리들의 집합)

MSA(MicroService Architecture) 를 지향하게 되면서 이를 위한 환경을 빠르게 제공해준다.

스프링 부트는 뭐든 빨리 개발할 수 있는 편리한 환경을 제공해주는 것 같다.

 

스프링 클라우드가 제공하는 기능은 다음과 같다.

  • 분산/버전 지정 구성(Distributed/versioned configuration)
  • 서비스 등록 및 발견(Service registration and discovery)
  • 라우팅(Routing)
  • 서비스 간 호출(Service-to-service calls)
  • 로드 밸런싱(Load balancing)
  • 서킷 브레이커(Circuit Breakers)
  • 전역 Lock(Global locks)
  • 리더쉽 선출 및 클러스터 상태(Leadership election and cluster state)
  • 분산 메시징(Distributed messaging)

 

스프링 클라우드 스트림(Spring Cloud Stream)

메시지 브로커(Message Broker) 와 쉽게 바인딩(Binding) 할 수 있는 마이크로 서비스 프레임 워크

스프링 부트에서 Apache Kafka 또는 RabbitMQ를 사용하여 메시지를 송수신 할 수 있다.

 

스프링 클라우드 스트림으로 메시지 브로커와 연결하기 위해서는 바인딩의 개념을 알고 있어야 한다.

 

 

RabbitMQ Binder

RabbitMQ Binder

RabbitMQ 에 대한 자세한 내용은 따로 정리가 필요할 것 같다. 일단 스프링 스트림에서 RabbitMQ 를 사용하기 위해 Topic Exchange, Queue, Binder 내용만 정리하려고한다.

  • Topic Exchange: 발행된 메시지를 해당하는 Queue 에 전달함
  • Queue: Topic Exchange 에 바인딩 되어 메시지를 저장하는 저장함
  • Binder: Topic Exchange 에 발행된 메시지를 어떤 Queue 에 저장되어야 하는지 정의함

간단한 코드 예제를 통해서 Spring Boot 에 RabbitMQ를 적용시켜보자.

 

 

Spring Cloud Stream + RabbitMQ

전체 소스코드는 Github 에 저장되어 있다.

github.com/Luidy/springboot-echo

 

pom.xmlspring-cloud-starter-stream-rabbit dependency 를 추가한다.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
  <version>1.3.0.RELEASE</version>
</dependency>

 

@Configuration 으로 메시지큐(RabbitMQ) 브로커 설정에 필요한 @Bean 을 입력한다. (@Configuration 어노테이션은 하나 이상의 @Bean 을 포함한 클래스에서 사용된다.)

Queue, TopicExchange Bean 을 생성하고 Binder 로 바인딩해준다. 

TopicExchageroutingKey 를 기준으로 Queue 에 전달한다. 

import com.ejjo.echos.service.MessageListener;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MQConfiguration {
    private String qName = "queue";
    private String exchangeName = "exchange";
    private String routeKey = "route";

    @Bean
    Queue queue() {
        Queue queue = new Queue(qName, false);
        return queue;
    }

    @Bean
    TopicExchange exchange(){
        return new TopicExchange(exchangeName);
    }

    @Bean
    Binding binding(Queue queue, TopicExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(routeKey);
    }
}

 

Publishing Message

메시지를 발행할 때에는 RabbitTemplate 를 호출한다.

RabbitTemplate 는 Spring Boot 에 자동으로 등록된 Bean 이다.

@Autowired
private RabbitTemplate rabbitTemplate;

public void testFunc() {
	rabbitTemplate.convertAndSend("exchange", "route", "publishing message.");
}

 

Consuming Message 

메시지 큐에 발행된 메시지를 수신하기 위해서는 수신되는 메시지를 처리하는 클래스(Listener)를 추가한다.

import org.springframework.stereotype.Component;

@Component
public class MessageListener {

    public void receiveMessage(String m){
        System.out.println("Message from Queue: "+m);
    }
}

 

수신을 처리하는 클래스를 메시지 큐와 연결해준다. 

@Configuration
public class MQConfiguration {
....

  @Bean
  SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
  MessageListenerAdapter listenerAdapter){
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueueNames(qName);
    container.setMessageListener(listenerAdapter);
    return container;
  }

  @Bean
  MessageListenerAdapter listenerAdapter(MessageListener listener) {
      return new MessageListenerAdapter(listener, "receiveMessage");
  }
}

 

이렇게 되면 Queue 에 입력되는 메시지를 MessageListener receiveMessage() 에서 입력받아 처리된다.

스프링에서 비동기 처리 + 메시지 브로커를 RabbitMQ 로 사용한다면 조금만 수정해서 사용가능할 것 같다.

 

 

참고 자료

cloud.spring.io/spring-cloud-stream-binder-rabbit/spring-cloud-stream-binder-rabbit.html

spring.io/projects/spring-cloud