Top 10 Spring Cloud Best Practices

Spring Cloud makes building microservices easier by providing essential tools for service discovery, configuration management, resiliency, API gateways, and observability. However, with the deprecation of many older components, it's important to follow modern best practices for scalability, maintainability, and security.

This article covers 10 best practices for building modern Spring Cloud applications without relying on outdated features like Netflix Zuul, Hystrix, Ribbon, RestTemplate, and Spring Cloud Sleuth.

Let’s dive in! 🚀

1️⃣ Use Spring Cloud Config for Centralized Configuration Management

Managing configurations inside each microservice is a nightmare. It leads to inconsistencies, deployment headaches, and security risks.

Best Practice: Use Spring Cloud Config Server to manage all configurations centrally.

🔹 Example: Setting Up Spring Cloud Config Server (bootstrap.yml)

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/my-org/config-repo  # ✅ Store configs in Git
server:
  port: 8888

💡 A centralized config server ensures all microservices stay in sync with consistent settings.

2️⃣ Use Spring Cloud Gateway Instead of Zuul

Netflix Zuul is deprecated. The better alternative is Spring Cloud Gateway, which supports WebFlux, better performance, and easy route filtering.

Best Practice: Use Spring Cloud Gateway for secure, efficient API routing.

🔹 Example: Configuring API Gateway (application.yml)

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/users/**
          filters:
            - StripPrefix=1  # ✅ Removes "/users" from forwarded requests

💡 Spring Cloud Gateway comes with built-in load balancing, authentication, and rate limiting.

3️⃣ Use Spring Cloud LoadBalancer Instead of Netflix Ribbon

Netflix Ribbon (client-side load balancing) is deprecated. Instead, use Spring Cloud LoadBalancer, which integrates with Spring Boot 3+ for automatic service discovery.

Best Practice: Use Spring Cloud LoadBalancer for scalable service-to-service communication.

🔹 Example: Configuring Load Balancer (application.yml)

spring:
  application:
    name: order-service
  cloud:
    loadbalancer:
      enabled: true

🔹 Example: Using WebClient Instead of RestTemplate

@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
    return WebClient.builder();
}

@Autowired
private WebClient.Builder webClientBuilder;

public String callUserService() {
    return webClientBuilder.build()
            .get()
            .uri("http://USER-SERVICE/users")
            .retrieve()
            .bodyToMono(String.class)
            .block();
}

💡 Spring Cloud LoadBalancer ensures efficient and reliable service-to-service calls.

4️⃣ Use Resilience4j Instead of Netflix Hystrix for Circuit Breaking

Hystrix is no longer maintained. Use Resilience4j, which offers circuit breaking, retries, rate limiting, and bulkheading in a lightweight package.

Best Practice: Use Resilience4j to handle failures gracefully.

🔹 Example: Using Resilience4j in a Service

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

@Service
public class OrderService {

    @CircuitBreaker(name = "orderService", fallbackMethod = "fallbackResponse")
    public String getOrders() {
        throw new RuntimeException("Service Down!");
    }

    public String fallbackResponse(Throwable t) {
        return "Fallback: Orders are currently unavailable.";
    }
}

💡 Resilience4j makes your microservices more resilient against failures.

5️⃣ Use OpenTelemetry Instead of Spring Cloud Sleuth for Tracing

Spring Cloud Sleuth is deprecated in favor of OpenTelemetry, which provides standardized distributed tracing for microservices.

Best Practice: Use OpenTelemetry to trace requests across multiple microservices.

🔹 Example: Adding OpenTelemetry Dependencies (pom.xml)

<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-api</artifactId>
    <version>1.27.0</version>
</dependency>

💡 OpenTelemetry allows you to track requests flowing across different microservices, helping in debugging and monitoring.

6️⃣ Use Centralized Logging with ELK or Loki

Each microservice generates logs separately, making debugging a nightmare. Centralized logging helps aggregate logs for easy monitoring.

Best Practice: Use ELK (Elasticsearch, Logstash, Kibana) or Loki for centralized logging.

🔹 Example: Sending Logs to Elasticsearch (logback-spring.xml)

<appender name="ELASTIC" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <destination>localhost:5000</destination>
</appender>

💡 With centralized logging, you can search and analyze logs across all microservices easily.

7️⃣ Secure APIs with OAuth2 & Spring Security

Basic authentication is not secure. Use OAuth2 and JWT for secure API authentication.

Best Practice: Use Spring Security with OAuth2 to protect APIs.

🔹 Example: Enabling OAuth2 Security (application.yml)

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://auth.example.com/

💡 OAuth2 ensures secure access to APIs without exposing credentials.

8️⃣ Use Kafka or RabbitMQ for Event-Driven Communication

Microservices should not rely too much on direct REST calls. Instead, use asynchronous messaging for better scalability and decoupling.

Best Practice: Use Spring Cloud Stream with Kafka or RabbitMQ.

🔹 Example: Kafka Message Producer

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

@Service
public class MessageProducer {
    private final KafkaTemplate<String, String> kafkaTemplate;

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

    public void sendMessage(String message) {
        kafkaTemplate.send("order-events", message);
    }
}

💡 Event-driven microservices improve performance and scalability.

9️⃣ Use Rate Limiting to Prevent API Overuse

Too many API requests can crash services. Rate limiting helps control API traffic.

Best Practice: Apply rate limiting with Spring Cloud Gateway.

🔹 Example: Configuring Rate Limiting (application.yml)

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter:
                  replenishRate: 5
                  burstCapacity: 10

💡 Rate limiting prevents API overload and service crashes.

🔟 Deploy Microservices with Kubernetes & Helm

Manually managing microservices doesn’t scale. Use Kubernetes and Helm to automate deployment.

Best Practice: Use Kubernetes for scalable microservices deployment.

🔹 Example: Kubernetes Deployment YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
        - name: user-service
          image: user-service:latest
          ports:
            - containerPort: 8080

💡 Kubernetes ensures high availability, scalability, and automated deployments.

🚀 Summary: 10 Best Practices for Spring Cloud

Use Spring Cloud Config for centralized configuration
Use Spring Cloud Gateway for API management
Use Spring Cloud LoadBalancer instead of Ribbon
Use Resilience4j for fault tolerance
Use OpenTelemetry for distributed tracing
Implement centralized logging with ELK or Loki
Use OAuth2 for API security
Use Kafka/RabbitMQ for asynchronous messaging
Apply rate limiting with Spring Cloud Gateway
Deploy microservices using Kubernetes

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare