자바 RabbitMQ 토픽 패턴은 TopicExchange 유형을 사용하며 라우팅 패턴(Direct)과 다르게 라우팅 매개변수가 모호한 일치를 지원한다. 라우팅 일치가 더 유연하기 때문에 더 자주 사용되는 패턴이다. 아키텍처는 다음 다이어그램과 같다.

RabbitMQ Topic Pattern

팁: RabbitMQ 작업 패턴을 어떤 것을 사용하든, 차이는 사용되는 교환 유형과 라우팅 매개변수에 있다.

1. 사전 튜토리얼

관련 지식을 이해하기 위해 먼저 다음 섹션을 읽어보십시오:

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는 어떠한 메시지도 받지 않습니다.