자바 RabbitMQ 토픽 패턴은 TopicExchange 유형을 사용하며 라우팅 패턴(Direct)과 다르게 라우팅 매개변수가 모호한 일치를 지원한다. 라우팅 일치가 더 유연하기 때문에 더 자주 사용되는 패턴이다. 아키텍처는 다음 다이어그램과 같다.
팁: RabbitMQ 작업 패턴을 어떤 것을 사용하든, 차이는 사용되는 교환 유형과 라우팅 매개변수에 있다.
1. 사전 튜토리얼
관련 지식을 이해하기 위해 먼저 다음 섹션을 읽어보십시오:
- RabbitMQ 기본 개념
- RabbitMQ 토픽 패턴 원리
- 자바 RabbitMQ 빠른 시작 (나중 섹션은 코드 반복 없이 핵심 코드만 표시되므로 반드시 읽어야 함)
- 자바 RabbitMQ Publish-Subscribe 패턴 섹션 (거의 동일한 코드 구문이지만 교환 유형과 라우팅 매개변수만 다름)
2. 토픽 교환 정의
Spring AMQP에서 Direct 교환에 해당하는 클래스는 TopicExchange이다. 교환을 Spring Boot 구성 클래스를 통해 정의한다.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// 교환을 정의
// 매개변수는 고유해야 하는 교환 이름
return new TopicExchange("tizi365.topic");
}
}
팁: 메시지 생성자와 소비자는 모두 교환을 필요로 한다.
3. 메시지 전송
우리는 메시지를 교환에 보내고, 교환은 라우팅 규칙에 따라 해당 큐에 메시지를 전달한다.
package com.tizi365.rabbitmq.service;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class SendService {
@Autowired
private RabbitTemplate template;
@Autowired
private TopicExchange topic;
// 데모를 위해 여기서는 매 초마다 메시지를 보내기 위해 예약된 작업을 사용한다
@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void send() {
// 메시지 내용
String message = "안녕, 세상아!";
// 메시지 보내기
// 첫 번째 매개변수는 교환 이름
// 두 번째 매개변수는 라우팅 키. 토픽 교환은 라우팅 키와 일치하는 큐에 메시지를 전달한다
// 세 번째 매개변수는 메시지 내용으로 직렬화된다면 모든 유형을 지원한다
template.convertAndSend(topic.getName(), "www.tizi365.com", message);
System.out.println("메시지가 전송되었습니다: '" + message + "'");
}
}
팁: convertAndSend 메서드의 두 번째 매개변수 "www.tizi365.com"에 주목하십시오. 이는 중요한 매개변수입니다.
4. 메시지 수신
4.1 큐 정의 및 익스체인지에 바인딩하기
메시지를 큐에서 소비하기 위해서는 먼저 큐를 정의하고 그런 다음 해당 큐를 대상 익스체인지에 바인딩해야 합니다. 아래에서 두 개의 큐가 정의되고 동일한 익스체인지에 바인딩됩니다.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// 익스체인지 정의
// 매개변수는 고유해야 하는 익스체인지 이름
return new TopicExchange("tizi365.topic");
}
@Bean
public Queue queue1() {
// 큐 1 정의
return new Queue("tizi365.topic.queue1");
}
@Bean
public Queue queue2() {
// 큐 2 정의
return new Queue("tizi365.topic.queue2");
}
@Bean
public Binding binding1(TopicExchange topic, Queue queue1) {
// 바인딩 관계 정의, 큐 1을 *.tizi365.com 라우팅 키로 익스체인지에 바인딩
return BindingBuilder.bind(queue1).to(topic).with("*.tizi365.com");
}
@Bean
public Binding binding2(TopicExchange topic, Queue queue2) {
// 바인딩 관계 정의, 큐 2를 *.baidu.com 라우팅 키로 익스체인지에 바인딩
return BindingBuilder.bind(queue2).to(topic).with("*.baidu.com");
}
}
팁: 큐 1과 큐 2를 익스체인지에 바인딩할 때 설정한 라우팅 키는 모두 * (별표) 와일드카드를 사용하여 단일 단어와 일치합니다. # (해시)로 변경하면 여러 단어와 일치합니다.
4.2 큐 리스너 정의
RabbitListener 주석을 사용하여 특정 큐에서 메시지를 소비하는 메시지 리스너를 정의합니다.
package com.tizi365.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
// 스프링이 현재 클래스를 관리하도록 설정
@Component
public class DemoListener {
// 리스너 정의, queues 매개변수를 통해 어떤 큐를 듣는지 지정
@RabbitListener(queues = "tizi365.topic.queue1")
public void receive1(String msg) {
System.out.println("큐 1로부터 메시지 수신: " + msg);
}
// 리스너 정의, queues 매개변수를 통해 어떤 큐를 듣는지 지정
@RabbitListener(queues = "tizi365.topic.queue2")
public void receive2(String msg) {
System.out.println("큐 2로부터 메시지 수신: " + msg);
}
}
익스체인지에 *.tizi365.com 라우팅 키가 있는 메시지와만 일치하기 때문에 오로지 큐 1만 메시지를 받을 수 있습니다. 반면에 라우팅 키가 일치하지 않기 때문에 큐 2는 어떠한 메시지도 받지 않습니다.