RabbitMQ-Nachricht, die mit Spring AMQP versendet wird

RabbitMQ Message Dispatching mit Spring AMQP

1. Einführung

In diesem Tutorial werden wir das Konzept vonfanout und den Themenaustausch mitSpring AMQP undRabbitMQ untersuchen.

Auf einer hohen Ebene werdenfanout exchangesbroadcast the same message to all bound queues, währendtopic exchanges einen Routing-Schlüssel fürpassing messages to a particular bound queue or queues verwenden.

Für dieses Tutorial wird empfohlen,Messaging With Spring AMQP vorher zu lesen.

2. Einrichten eines Fanout-Austauschs

Richten wir einen Fanout-Austausch mit zwei daran gebundenen Warteschlangen ein. Wenn wir eine Nachricht an diese Vermittlungsstelle senden, erhalten beide Warteschlangen die Nachricht. Unser Fanout-Austausch ignoriert alle in der Nachricht enthaltenen Routing-Schlüssel.

Mit Spring AMQP können wir alle Deklarationen von Warteschlangen, Austauschen und Bindungen in einemDeclarables-Objekt zusammenfassen:

@Bean
public Declarables fanoutBindings() {
    Queue fanoutQueue1 = new Queue("fanout.queue1", false);
    Queue fanoutQueue2 = new Queue("fanout.queue2", false);
    FanoutExchange fanoutExchange = new FanoutExchange("fanout.exchange");

    return new Declarables(
      fanoutQueue1,
      fanoutQueue2,
      fanoutExchange,
      bind(fanoutQueue1).to(fanoutExchange),
      BindingBuilder.bind(fanoutQueue2).to(fanoutExchange));
}

3. Einrichten eines Themenaustauschs

Jetzt richten wir auch einen Themenaustausch mit zwei Warteschlangen mit jeweils unterschiedlichen Bindungsmustern ein:

@Bean
public Declarables topicBindings() {
    Queue topicQueue1 = new Queue(topicQueue1Name, false);
    Queue topicQueue2 = new Queue(topicQueue2Name, false);

    TopicExchange topicExchange = new TopicExchange(topicExchangeName);

    return new Declarables(
      topicQueue1,
      topicQueue2,
      topicExchange,
      BindingBuilder
        .bind(topicQueue1)
        .to(topicExchange).with("*.important.*"),
      BindingBuilder
        .bind(topicQueue2)
        .to(topicExchange).with("#.error"));
}

A topic exchange allows us to bind queues to it with different key patterns. Dies ist sehr flexibel und ermöglicht es uns, mehrere Warteschlangen mit demselben Muster oder sogar mehrere Muster an dieselbe Warteschlange zu binden.

Wenn der Routing-Schlüssel der Nachricht mit dem Muster übereinstimmt, wird er in die Warteschlange gestellt. If a queue has multiple bindings which match the message’s routing key, only one copy of the message is placed on the queue.

In unseren Bindungsmustern kann ein Sternchen ("*") verwendet werden, um ein Wort an einer bestimmten Position zu finden, oder ein Nummernzeichen ("#"), um null oder mehr Wörter zu finden.

UnseretopicQueue1 erhalten also Nachrichten mit Routing-Schlüsseln mit einem Drei-Wort-Muster, wobei das mittlere Wort „wichtig“ ist - zum Beispiel:“user.important.error” oder“blog.important.notification”.

Und unseretopicQueue2 empfangen Nachrichten, deren Routing-Schlüssel mit dem Wortfehler enden. Übereinstimmende Beispiele sind“error”,“user.important.error” oder“blog.post.save.error”.

4. Einrichten eines Produzenten

Wir verwenden dieconvertAndSend-Methode derRabbitTemplate, um unsere Beispielnachrichten zu senden:

    String message = " payload is broadcast";
    return args -> {
        rabbitTemplate.convertAndSend(FANOUT_EXCHANGE_NAME, "", "fanout" + message);
        rabbitTemplate.convertAndSend(TOPIC_EXCHANGE_NAME, ROUTING_KEY_USER_IMPORTANT_WARN,
            "topic important warn" + message);
        rabbitTemplate.convertAndSend(TOPIC_EXCHANGE_NAME, ROUTING_KEY_USER_IMPORTANT_ERROR,
            "topic important error" + message);
    };

DasRabbitTemplate bietet viele überladeneconvertAndSend()-Methoden für verschiedene Austauschtypen.

Wenn wir eine Nachricht an eine Fanout-Vermittlung senden, wird der Routing-Schlüssel ignoriert und die Nachricht an alle gebundenen Warteschlangen weitergeleitet.

Wenn wir eine Nachricht an den Themenaustausch senden, müssen wir einen Routing-Schlüssel übergeben. Basierend auf diesem Weiterleitungsschlüssel wird die Nachricht an bestimmte Warteschlangen zugestellt.

5. Verbraucher konfigurieren

Lassen Sie uns abschließend vier Konsumenten einrichten - einen für jede Warteschlange -, um die produzierten Nachrichten aufzunehmen:

    @RabbitListener(queues = {FANOUT_QUEUE_1_NAME})
    public void receiveMessageFromFanout1(String message) {
        System.out.println("Received fanout 1 message: " + message);
    }

    @RabbitListener(queues = {FANOUT_QUEUE_2_NAME})
    public void receiveMessageFromFanout2(String message) {
        System.out.println("Received fanout 2 message: " + message);
    }

    @RabbitListener(queues = {TOPIC_QUEUE_1_NAME})
    public void receiveMessageFromTopic1(String message) {
        System.out.println("Received topic 1 (" + BINDING_PATTERN_IMPORTANT + ") message: " + message);
    }

    @RabbitListener(queues = {TOPIC_QUEUE_2_NAME})
    public void receiveMessageFromTopic2(String message) {
        System.out.println("Received topic 2 (" + BINDING_PATTERN_ERROR + ") message: " + message);
    }

We configure consumers using the @RabbitListener annotation. Das einzige hier übergebene Argument ist der Name der Warteschlange. Verbraucher sind sich hier von Umtausch- oder Weiterleitungsschlüsseln nicht bewusst.

6. Beispiel ausführen

Unser Beispielprojekt ist eine Spring Boot-Anwendung. Daher wird die Anwendung zusammen mit einer Verbindung zu RabbitMQ initialisiert und alle Warteschlangen, Austausche und Bindungen eingerichtet.

Standardmäßig erwartet unsere Anwendung eine RabbitMQ-Instanz, die auf dem lokalen Host auf Port 5672 ausgeführt wird. Wir können diese und andere Standardeinstellungen inapplication.yaml ändern.

Unser Projekt stellt den HTTP-Endpunkt auf dem URI -/broadcast - bereit, der POSTs mit einer Nachricht im Anforderungshauptteil akzeptiert.

Wenn wir eine Anfrage an diese URI mit dem Body "Test" senden, sollten wir in der Ausgabe etwas Ähnliches sehen:

Received fanout 1 message: fanout payload is broadcast
Received topic 1 (*.important.*) message: topic important warn payload is broadcast
Received topic 2 (#.error) message: topic important error payload is broadcast
Received fanout 2 message: fanout payload is broadcast
Received topic 1 (*.important.*) message: topic important error payload is broadcast

Die Reihenfolge, in der wir diese Nachrichten sehen, ist natürlich nicht garantiert.

7. Fazit

In diesem kurzen Tutorial haben wir Fanout und Themenaustausch mit Spring AMQP und RabbitMQ behandelt.

Der vollständige Quellcode und alle Codefragmente für dieses Lernprogramm sind aufGitHub repository verfügbar.