Especialização em Backend com Java & Spring Boot • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Publicação no RabbitMQ com Jackson2JsonMessageConverter

package com.empresa.api.config;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

    @Bean
    public MessageConverter jsonMessageConverter() {
        // Sem isto, o RabbitTemplate serializa em Java nativo (binário, ilegível e frágil).
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public RabbitTemplate rabbitTemplate(org.springframework.amqp.rabbit.connection.ConnectionFactory cf,
                                          MessageConverter converter) {
        RabbitTemplate template = new RabbitTemplate(cf);
        template.setMessageConverter(converter);
        return template;
    }
}
package com.empresa.api.messaging;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

public record PedidoEvento(Long pedidoId, String status) {}

@Service
public class PedidoPublisher {

    private final RabbitTemplate rabbitTemplate;

    public PedidoPublisher(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    public void publicarNovoPedido(PedidoEvento evento) {
        rabbitTemplate.convertAndSend("pedidos.exchange", "pedidos.novos", evento);
    }
}

💻 Código de Exemplo 02 — Produção Kafka com Chave de Partição e Callback Assíncrono

package com.empresa.api.messaging;

import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Service;

@Service
public class FaturamentoEventPublisher {

    private final KafkaTemplate<String, FaturamentoEvento> kafkaTemplate;

    public FaturamentoEventPublisher(KafkaTemplate<String, FaturamentoEvento> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void publicar(FaturamentoEvento evento) {
        // Chave = clienteId: garante que eventos do mesmo cliente caiam sempre na mesma
        // partição, preservando a ordem relativa entre eles.
        kafkaTemplate.send("faturamento-events", evento.clienteId().toString(), evento)
            .whenComplete((SendResult<String, FaturamentoEvento> resultado, Throwable erro) -> {
                if (erro != null) {
                    System.err.println("Falha ao publicar evento de faturamento: " + erro.getMessage());
                } else {
                    System.out.println("Evento publicado na partição " +
                        resultado.getRecordMetadata().partition());
                }
            });
    }
}

record FaturamentoEvento(Long clienteId, double valor) {}

💻 Código de Exemplo 03 — Consumo Kafka com Ack Manual e Consumer Group

package com.empresa.api.messaging;

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

@Component
public class FaturamentoEventListener {

    @KafkaListener(topics = "faturamento-events", groupId = "faturamento-service")
    public void consumir(FaturamentoEvento evento, Acknowledgment ack) {
        try {
            System.out.println("Processando faturamento do cliente " + evento.clienteId());
            // Persistência/regra de negócio idempotente aqui.
            ack.acknowledge(); // commit manual do offset: só avança após sucesso confirmado
        } catch (Exception ex) {
            // Não confirma o offset: o DefaultErrorHandler decide retry/DLT conforme configurado.
            throw ex;
        }
    }
}