💻 Exemplos: Capítulo 15: Mensageria Assíncrona e Eventos com RabbitMQ e Kafka
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;
}
}
}