Envio da mensagem do RabbitMQ com o Spring AMQP

Envio da mensagem do RabbitMQ com o Spring AMQP

1. Introdução

Neste tutorial, vamos explorar o conceito defanoute trocas de tópicos comSpring AMQPeRabbitMQ.

Em um nível alto,fanout exchanges irábroadcast the same message to all bound queues, enquantotopic exchanges usará uma chave de roteamento parapassing messages to a particular bound queue or queues.

A leitura anterior deMessaging With Spring AMQP é recomendada para este tutorial.

2. Configurando uma troca de fãs

Vamos configurar um fanout exchange com duas filas vinculadas a ele. Quando enviamos uma mensagem para essa troca, as duas filas receberão a mensagem. Nossa troca de fanout ignora qualquer chave de roteamento incluída na mensagem.

Spring AMQP nos permite agregar todas as declarações de filas, trocas e ligações em um objetoDeclarables:

@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. Configurando uma troca de tópicos

Agora, também configuraremos uma troca de tópicos com duas filas, cada uma com um padrão de ligação diferente:

@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. Isso é muito flexível e nos permite vincular várias filas com o mesmo padrão ou até mesmo vários padrões à mesma fila.

Quando a chave de roteamento da mensagem corresponder ao padrão, ela será colocada na fila. If a queue has multiple bindings which match the message’s routing key, only one copy of the message is placed on the queue.

Nossos padrões de encadernação podem usar um asterisco ("*") para corresponder a uma palavra em uma posição específica ou um sinal de libra ("#") para corresponder a zero ou mais palavras.

Portanto, nossotopicQueue1 receberá mensagens com chaves de roteamento com um padrão de três palavras, sendo a palavra do meio "importante" - por exemplo:“user.important.error” ou“blog.important.notification”.

E, nossotopicQueue2 receberá mensagens que possuem chaves de roteamento terminando com a palavra erro; exemplos correspondentes são“error”,“user.important.error” ou“blog.post.save.error”.

4. Configurando um produtor

Usaremos o métodoconvertAndSend deRabbitTemplate para enviar nossas mensagens de amostra:

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

ORabbitTemplate fornece muitos métodosconvertAndSend() sobrecarregados para diferentes tipos de troca.

Quando enviamos uma mensagem para uma troca de fanout, a chave de roteamento é ignorada e a mensagem é passada para todas as filas ligadas.

Quando enviamos uma mensagem para a troca de tópicos, precisamos passar uma chave de roteamento. Com base nessa chave de roteamento, a mensagem será entregue em filas específicas.

5. Configurando Consumidores

Finalmente, vamos configurar quatro consumidores - um para cada fila - para pegar as mensagens produzidas:

    @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. O único argumento passado aqui é o nome das filas. Os consumidores não estão cientes aqui de trocas ou chaves de roteamento.

6. Executando o Exemplo

Nosso projeto de amostra é um aplicativo Spring Boot e, portanto, inicializará o aplicativo juntamente com uma conexão com o RabbitMQ e configurará todas as filas, trocas e ligações.

Por padrão, nosso aplicativo espera uma instância RabbitMQ em execução no host local na porta 5672. Podemos modificar este e outros padrões emapplication.yaml.

Nosso projeto expõe o endpoint HTTP no URI -/broadcast - que aceita POSTs com uma mensagem no corpo da solicitação.

Quando enviamos uma solicitação para esse URI com o corpo "Test", devemos ver algo semelhante a este na saída:

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

A ordem em que veremos essas mensagens não é, obviamente, garantida.

7. Conclusão

Neste tutorial rápido, abordamos trocas de fanout e tópicos com Spring AMQP e RabbitMQ.

O código-fonte completo e todos os trechos de código para este tutorial estão disponíveis noGitHub repository.