티스토리 뷰

728x90
반응형

웹 애플리케이션에서 데이터를 동기식으로 주고받으면, 라운드 트립(Round-Trp : 클라이언트-서버 간 메시지를 교환하는 총 시간) 시간이 오래 걸릴수록, 메시지를 요청하는 쪽에서는 Blocking 되는 시간이 길어집니다. 그러므로, 비동기 식 메시지 교환 방법을 많이 사용하는데, 메시지 큐는 대표적으로 비동기식 데이터 송수신을 지원하는 미들웨어입니다. ActiveMQ는 Java Message Service (=JMS) 기반으로 통신을 제어하는 메시지 큐입니다. RabbitMQ은 AMQP 프로토콜을 기반으로 메시지 통신을 수행하지만, ActiveMQ는 JMS를 기반으로 메시지 통신을 수행하기 때문에, RabbitMQ와 ActiveMQ 간 메시지 교환을 불가능합니다. 즉, 프로토콜이 달라 데이터 교환이 어려운 것이죠. Kafka는 대용량 분산 시스템용으로 많이 사용되고, 그 이외에 경우는 ActiveMQ와 RabbitMQ를 많이 사용한다고 합니다. 메시지 큐는 사용해보고, 애플리케이션 개발환경에 더 적합한 메시지 큐를 사용하는 것 같습니다. 

이번 포스팅에서는 SpringBoot에 JMS 기반인 ActiveMQ로 메시지를 송수신하는 방법에 대해 알아보겠습니다.

Springboot ActiveMQ 용 프로젝트 다운로드

https://start.spring.io/ 사이트에 접속하여 실습할 프로젝트 환경을 설정한 뒤 디펜던시 항목에 Spring for Apache ActiveMQ 5 항목을 선택하여 프로젝트를 다운로드합니다.

ActiveMQ 디펜던시를 추가한 SpringBoot 프로젝트 다운로드

다운로드한 프로젝트를 압축 해제한 뒤, build.gradle 파일을 열어보면 디펜던시에 ActiveMQ가 추가된 것을 확인할 수 있습니다.

implementation 'org.springframework.boot:spring-boot-starter-activemq'

ActiveMQ  용어 정의

JMS를 설명하는 용어 중 Message Broker, Destination, Queue, Topic에 대한 정의를 먼저 이해해야 합니다. 아래 용어는 JMS 소스코드를 작성할 때 사용되는 개념이므로, 정의를 통해 한번 알아보겠습니다.

  • Message Broker : 메시지를 목적지로 건네주는 중개자(Broker)
  • Destination : 메세를 수신받을 주소지
  • Queue : 큐의 메시지를 Consumer 간 경쟁하여 가져 가는 모델
  • Topic : Topic에 메시지를 발행 및 구독하여 메시지를 교환하는 모델, Topic 구독자는 모두 동일하게 메시지를 가져감

메시지 Receiver 클래스 작성하기

메시지를 수신받을 때, Email이라는 POJO 객체로 데이터를 수신받을 수 있도록 클래스를 Email클래스를 작성해보겠습니다. 

package com.example.demo;

public class Email {

    private String to;
    private String body;

    public Email() {
    }

    public Email(String to, String body) {
        this.to = to;
        this.body = body;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    @Override
    public String toString() {
        return String.format("Email{to=%s, body=%s}", getTo(), getBody());
    }

}

다음으로, 메시지를 수신받을 Receiver 클래스를 작성해보겠습니다.

package com.example.demo;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class Receiver {

    @JmsListener(destination = "mailbox", containerFactory = "myFactory")
    public void receiveMessage(Email email) {
        System.out.println("Received <" + email + ">");
    }

}

@JmsListener 어노테이션으로 destination과 containerFactory를 설정하였습니다. destination은 이후 메시지를 전송할 목적지 주소라고 이해할 수 있고, containerFactory는 메시지 수신을 대기하는 리스너 역할을 하는 컨테이너라고 하지만, 꼭 지정하지 않아도 되는 속성입니다. 

메시지 Sender 구현하기

Sender 클래스는 별로도 작성하지 않고, Main함수에 바로 작성하겠습니다.

import javax.jms.ConnectionFactory;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;

@SpringBootApplication
@EnableJms
public class Application {

  @Bean
  public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                          DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    // This provides all boot's default to this factory, including the message converter
    configurer.configure(factory, connectionFactory);
    // You could still override some of Boot's default if necessary.
    return factory;
  }

  @Bean // Serialize message content to json using TextMessage
  public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("_type");
    return converter;
  }

  public static void main(String[] args) {
    // Launch the application
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

    JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);

    // Send a message with a POJO - the template reuse the message converter
    System.out.println("Sending an email message.");
    jmsTemplate.convertAndSend("mailbox", new Email("info@example.com", "Hello"));
  }

}

@EnableJms은 @JmsListener를 찾아서 메시지 리스너 컨테이너를 생성을 지시합니다. myFactory()는 앞서 @JmsListener에서 정의했던 containerFactory이고, DefaultJmsListenerContainerFactory를 사용하여 스프링 부트에서 기본적으로 제공하는 컨테이너를 사용하였습니다. 다음으로 jacksonJmsMessageConverter() 메서드를 통해, 메시지 객체를 직렬화 방법을 TEXT 방식으로 선택하였습니다. 그리고 JmsTemplate 객체를 이용하여 메시지를 발행합니다.

main클래스를 실행하면, "mailbox"로 정의한 Destination으로 새로 생성한 Email객체를 TEXT로 전송하여, Receive클래스에서 메시지를 받아 출력하는 것을 확인할 수 있습니다.

Sending an email message.
Received <Email{to=info@example.com, body=Hello}>

이상으로 Springboot에서 JMS를 이용한 ActiveMQ와 연동하는 방법에 대해 알아보았습니다.

728x90
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함