📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
Learn how to implement event-driven communication in Java microservices using Kafka. Step-by-step guide with real-world e-commerce example and full working code.
I am a bestseller Udemy Instructor. Check out my top 10 Udemy courses with discounts: My Udemy Courses — Ramesh Fadatare.
🧾 Introduction
Event-driven communication is the backbone of modern, scalable microservices architectures.
✅ Instead of tight synchronous REST calls, services communicate via events asynchronously.
✅ It improves scalability, resilience, and flexibility.
In this guide, you’ll learn how to implement Event-Driven Microservices using Kafka — through a real-world e-commerce example:

✅ Project Setup: E-Commerce Microservices System
We’ll build a system with 3 services:

Communication Style: Services publish and listen to Kafka events.
📦 Step 1: Set Up Kafka Locally
You need a running Kafka instance. Use Docker Compose for simplicity.
# docker-compose.yml
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_HOST_NAME: localhost
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
➡️ Run:
docker-compose up
✅ Kafka broker running at localhost:9092
.
📦 Step 2: Create Order Service (Producer)
2.1 Add Dependencies (Spring Boot + Kafka)
<!-- Order Service pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
2.2 Configure Kafka Properties
Open the application.properties file and add the following properties:
# application.properties
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
2.3 Create Event Class
public class OrderPlacedEvent {
private String orderId;
private String productId;
private int quantity;
public OrderPlacedEvent() {}
public OrderPlacedEvent(String orderId, String productId, int quantity) {
this.orderId = orderId;
this.productId = productId;
this.quantity = quantity;
}
// Getters and Setters
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public String getProductId() { return productId; }
public void setProductId(String productId) { this.productId = productId; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}
2.4 Publish Event to Kafka
@Service
public class OrderService {
private final KafkaTemplate<String, OrderPlacedEvent> kafkaTemplate;
public OrderService(KafkaTemplate<String, OrderPlacedEvent> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public String placeOrder(String productId, int quantity) {
String orderId = UUID.randomUUID().toString();
OrderPlacedEvent event = new OrderPlacedEvent(orderId, productId, quantity);
kafkaTemplate.send("order-topic", event);
System.out.println("✅ OrderPlacedEvent published for Order ID: " + orderId);
return orderId;
}
}
2.5 Create REST API
Let’s build a simple REST API that internally calls OrderService and in turn OrderService publishes events to the Kafka topic.
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping
public ResponseEntity<String> placeOrder(@RequestBody OrderRequest request) {
String orderId = orderService.placeOrder(request.getProductId(), request.getQuantity());
return ResponseEntity.ok("✅ Order placed successfully. Order ID: " + orderId);
}
}
OrderRequest.java
(DTO for incoming JSON)
public class OrderRequest {
private String productId;
private int quantity;
public String getProductId() { return productId; }
public void setProductId(String productId) { this.productId = productId; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}
2.6 Kafka Producer Configuration (Optional for JSON support)
If you want to send the OrderPlacedEvent
as JSON, use this:
@Bean
public ProducerFactory<String, OrderPlacedEvent> producerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return new DefaultKafkaProducerFactory<>(config);
}
@Bean
public KafkaTemplate<String, OrderPlacedEvent> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
2.7 Sample API Test (Postman or Curl)
URL: POST http://localhost:8080/api/orders
Headers: Content-Type: application/json
Request Body:
{
"productId": "P-1001",
"quantity": 3
}
Expected Response:
✅ Order placed successfully. Order ID: f4a8e9e0-712a-4c8e-a303-abc123456789
You should also see a log like:
✅ OrderPlacedEvent published for Order ID: f4a8e9e0-712a-4c8e-a303-abc123456789
📦 Step 3: Create Payment Service (Consumer + Producer)
3.1 Add Dependencies
<!-- Payment Service pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
</dependencies>
3.2 Kafka Config
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=payment-service-group
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
3.3 Listen to OrderPlacedEvent
and Publish PaymentCompletedEvent
@Service
public class PaymentService {
private final KafkaTemplate<String, PaymentCompletedEvent> kafkaTemplate;
public PaymentService(KafkaTemplate<String, PaymentCompletedEvent> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
@KafkaListener(topics = "order-topic", groupId = "payment-service-group")
public void processPayment(OrderPlacedEvent event) {
System.out.println("Processing payment for Order ID: " + event.getOrderId());
// Simulate payment success
PaymentCompletedEvent paymentCompleted = new PaymentCompletedEvent(event.getOrderId(), "SUCCESS");
kafkaTemplate.send("payment-topic", paymentCompleted);
System.out.println("PaymentCompletedEvent published for Order ID: " + event.getOrderId());
}
}
PaymentCompletedEvent
public class PaymentCompletedEvent {
private String orderId;
private String status;
// Constructors, Getters, Setters
}
📦 Step 4: Create Inventory Service (Consumer)
4.1 Add Dependencies and Kafka Config (Same as before)
<!-- Inventory Service pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
</dependencies>
4.2 Listen to PaymentCompletedEvent
@Service
public class InventoryService {
@KafkaListener(topics = "payment-topic", groupId = "inventory-service-group")
public void reserveStock(PaymentCompletedEvent event) {
if ("SUCCESS".equals(event.getStatus())) {
System.out.println("Reserving stock for Order ID: " + event.getOrderId());
// Inventory logic here
} else {
System.out.println("Payment failed. No stock reserved for Order ID: " + event.getOrderId());
}
}
}
✅ Inventory only reserves stock if payment is successful.
🏗️ Overall Architecture

✅ Full Event-Driven asynchronous communication
✅ No tight service-to-service calls
✅ Each service is independent but coordinated via events
✅ Final Thoughts
✅ Event-Driven Architecture with Kafka decouples services.
✅ It makes Java microservices scalable, resilient, and independent.
✅ Each service focuses only on its domain — communicating via reliable, asynchronous events.
Good developers build services.
Great developers make services work together smartly with events.
Master event-driven design — and your Java microservices will scale effortlessly in real-world production.
Comments
Post a Comment
Leave Comment