Envoi de messages RabbitMQ avec Spring AMQP

Envoi de messages RabbitMQ avec Spring AMQP

1. introduction

Dans ce didacticiel, nous allons explorer le concept defanout et les échanges de sujets avecSpring AMQP etRabbitMQ.

À un niveau élevé,fanout exchanges utiliserabroadcast the same message to all bound queues, tandis quetopic exchanges utilisera une clé de routage pourpassing messages to a particular bound queue or queues.

La lecture préalable deMessaging With Spring AMQP est recommandée pour ce didacticiel.

2. Configuration d'un échange de fanout

Configurons un échange de distribution avec deux files d'attente liées. Lorsque nous envoyons un message à cet échange, les deux files d'attente le reçoivent. Notre échange fanout ignore toutes les clés de routage incluses dans le message.

Spring AMQP nous permet d'agréger toutes les déclarations de files d'attente, d'échanges et de liaisons dans un objetDeclarables:

@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. Configurer un échange de sujet

À présent, nous allons également configurer un échange de sujets avec deux files d'attente, chacune avec un modèle de liaison différent:

@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. Ceci est très flexible et nous permet de lier plusieurs files d'attente avec le même modèle ou même plusieurs modèles à la même file d'attente.

Lorsque la clé de routage du message correspond au modèle, il est placé dans la file d’attente. If a queue has multiple bindings which match the message’s routing key, only one copy of the message is placed on the queue.

Nos modèles de liaison peuvent utiliser un astérisque ("*") pour faire correspondre un mot à une position spécifique ou un signe dièse ("#") pour faire correspondre un mot ou plus à zéro.

Ainsi, nostopicQueue1 recevront des messages qui ont des clés de routage ayant un modèle de trois mots avec le mot du milieu étant «important» - par exemple:“user.important.error” ou“blog.important.notification”.

Et, nostopicQueue2 recevront des messages dont les clés de routage se terminent par le mot erreur; les exemples correspondants sont“error”,“user.important.error” ou“blog.post.save.error”.

4. Mise en place d'un producteur

Nous utiliserons la méthodeconvertAndSend desRabbitTemplate pour envoyer nos exemples de messages:

    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);
    };

LeRabbitTemplate fournit de nombreuses méthodesconvertAndSend() surchargées pour différents types d'échange.

Lorsque nous envoyons un message à un échange fanout, la clé de routage est ignorée et le message est transmis à toutes les files d'attente liées.

Lorsque nous envoyons un message à l’échange de sujets, nous devons transmettre une clé de routage. Sur la base de cette clé de routage, le message sera remis à des files d'attente spécifiques.

5. Configuration des consommateurs

Enfin, configurons quatre consommateurs - un pour chaque file d’attente - pour récupérer les messages produits:

    @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. Le seul argument passé ici est le nom des files d'attente. Les consommateurs ne sont pas au courant des échanges ou des clés de routage.

6. Exécuter l'exemple

Notre exemple de projet est une application Spring Boot. Il initialisera donc l'application avec une connexion à RabbitMQ et configurera toutes les files d'attente, échanges et liaisons.

Par défaut, notre application s'attend à une instance RabbitMQ s'exécutant sur l'hôte local sur le port 5672. Nous pouvons modifier ceci et d'autres valeurs par défaut dansapplication.yaml.

Notre projet expose le point de terminaison HTTP sur l'URI -/broadcast - qui accepte les POST avec un message dans le corps de la requête.

Lorsque nous envoyons une requête à cet URI avec le corps «Test», nous devrions voir quelque chose de similaire à ceci dans la sortie:

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

L'ordre dans lequel nous verrons ces messages n'est bien entendu pas garanti.

7. Conclusion

Dans ce rapide didacticiel, nous avons abordé les échanges en fanout et en sujets avec Spring AMQP et RabbitMQ.

Le code source complet et tous les extraits de code de ce didacticiel sont disponibles sur lesGitHub repository.