Skip to content

How to Learn Spring Cloud Microservices from Scratch

Problem

I tried to learn Spring Cloud microservices last year. I bought a course, watched videos about Eureka, Ribbon, Hystrix, Zuul—then discovered half of them were deprecated. Netflix OSS components I spent weeks learning? Maintenance mode. Replaced by Spring Cloud Gateway and Resilience4j.

But the bigger problem: even after the course, I couldn’t build a microservices system from scratch. I knew what Eureka did, but I didn’t know WHY I needed it first. I could configure a gateway, but didn’t understand the order components should be implemented.

A Reddit user captured this perfectly: “Paid courses are far from what a good book studied carefully can offer.” The issue isn’t just outdated content—it’s that most resources don’t give you a structured, practical path.

What Makes Learning Spring Cloud Hard

I identified four main problems:

Problem 1: Overwhelming Complexity
-----------------------------------
Spring Cloud has 20+ components. Which do I learn first?
Which are essential? Which are optional?
Problem 2: Fragmented Resources
-------------------------------
Official docs + blog posts + YouTube + paid courses
No single cohesive path. Pieces don't connect.
Problem 3: Rapid Evolution
--------------------------
Netflix OSS (Eureka, Hystrix, Zuul) → deprecated
Spring Cloud 2020+ → new stack
Tutorials from 2022 are already outdated.
Problem 4: Theory-Practice Gap
-------------------------------
Reading books alone = no muscle memory
Coding without understanding = cargo-cult programming

After struggling through this, I found a learning sequence that actually works.

The Solution: A 6-Step Path

Here’s the order I recommend—each step builds on the previous, mirroring how you’d implement a real system:

Step 1: Spring Boot Fundamentals (1-2 weeks)
Step 2: Microservices Concepts (1 week)
Step 3: Service Discovery with Eureka (1 week)
Step 4: API Gateway with Spring Cloud Gateway (1 week)
Step 5: Config Server (1 week)
Step 6: Resilience Patterns (1-2 weeks)

Step 1: Master Spring Boot First (1-2 Weeks)

I made the mistake of jumping straight into Spring Cloud. Don’t.

Before touching microservices, you need solid understanding of:

  • Dependency Injection and IoC Container
  • Spring Boot auto-configuration (know what it hides)
  • RESTful API development
  • Spring Data JPA
  • Testing with @SpringBootTest

Why this matters: Spring Cloud builds on Spring Boot. Without this foundation, you’ll struggle with configuration mysteries and won’t know how to troubleshoot when services won’t start.

If you can’t explain what happens when you add @SpringBootApplication, go back and learn Spring Boot basics first.

Step 2: Understand Microservices Architecture (1 Week)

This is where I see developers skip ahead and make bad design decisions later.

Learn the core concepts:

  • Service decomposition: How do you split a monolith? By business capability? By domain?
  • Communication patterns: REST vs gRPC vs messaging. When to use each.
  • Data management: Database per service, sagas, eventual consistency
  • Distributed challenges: Network latency, partial failures, CAP theorem

Why this matters: Technology choices depend on architectural understanding. Without this, you’ll put business logic in your API gateway or create distributed monoliths.

Step 3: Service Discovery with Eureka (1 Week)

Now we implement our first Spring Cloud component. Service discovery solves a fundamental problem: how do services find each other when IP addresses change?

Project structure:

project-structure.txt
spring-cloud-demo/
|-- eureka-server/ # Service registry (port 8761)
|-- user-service/ # Microservice 1 (port 8081)
|-- order-service/ # Microservice 2 (port 8082)

Eureka Server setup:

EurekaServerApplication.java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
eureka-server/application.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false # Don't register itself
fetch-registry: false # Don't fetch registry
service-url:
defaultZone: http://localhost:8761/eureka/

Registering a microservice:

UserServiceApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
user-service/application.yml
spring:
application:
name: user-service
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

After starting both, visit http://localhost:8761 and you’ll see USER-SERVICE registered.

Common mistake: Confusing client-side discovery (Eureka) with server-side discovery (like Kubernetes). With Eureka, clients query the registry directly.

Step 4: API Gateway with Spring Cloud Gateway (1 Week)

Now you have multiple services. But clients don’t want to know every service’s address. Enter the API Gateway.

Why a gateway?

  • Single entry point for clients
  • Request routing and filtering
  • Rate limiting, authentication, logging
ApiGatewayApplication.java
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
api-gateway/application.yml
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # Load-balanced via Eureka
predicates:
- Path=/api/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

Now clients call http://localhost:8080/api/users/1 and the gateway routes to the user-service.

Common mistake: Putting business logic in the gateway. Don’t. The gateway is for cross-cutting concerns: auth, rate limiting, logging. Business logic goes in services.

Step 5: Centralized Configuration (1 Week)

Running multiple services? Managing configuration across them becomes a nightmare. Config Server centralizes everything.

ConfigServerApplication.java
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
config-server/application.yml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-org/config-repo
default-label: main

Your Git repo stores configs like:

config-repo/user-service.yml
spring:
datasource:
url: jdbc:postgresql://db:5432/users
username: ${DB_USERNAME}
password: ${DB_PASSWORD}

Services fetch their config from the server on startup:

user-service/bootstrap.yml
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888

Common mistake: Storing secrets in plain text. Use encryption:

Terminal window
# Encrypt a value
curl http://localhost:8888/encrypt -d my-secret-password
# Store in config
spring:
datasource:
password: '{cipher}AQCGy...'

Step 6: Resilience Patterns with Resilience4j (1-2 Weeks)

In distributed systems, services fail. Network calls timeout. How do you prevent cascading failures?

Key patterns:

  • Circuit Breaker: Stop calling a failing service
  • Retry: Retry failed requests with backoff
  • Rate Limiter: Prevent service overload
  • Bulkhead: Isolate failures to prevent spread
OrderService.java
@Service
public class OrderService {
private final RestTemplate restTemplate;
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
@Retry(name = "userService")
public User getUser(Long userId) {
return restTemplate.getForObject(
"http://user-service/api/users/" + userId,
User.class
);
}
// Fallback when circuit is open or retries exhausted
public User getUserFallback(Long userId, Exception e) {
return new User(userId, "Unknown", "Service temporarily unavailable");
}
}
order-service/application.yml
resilience4j:
circuitbreaker:
instances:
userService:
sliding-window-size: 10
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
retry:
instances:
userService:
max-attempts: 3
wait-duration: 1s

What happens:

  • Circuit starts CLOSED (requests flow normally)
  • After 50% failures in 10 calls, circuit opens
  • Open circuit: all requests go to fallback immediately
  • After 10 seconds, circuit transitions to half-open
  • One test request passes through; if successful, circuit closes

Common mistake: Not implementing fallbacks. Without fallbacks, you get exceptions, not graceful degradation.

Running Everything Together

For local development, Docker Compose orchestrates all services:

docker-compose.yml
version: '3.8'
services:
eureka-server:
build: ./eureka-server
ports:
- "8761:8761"
config-server:
build: ./config-server
ports:
- "8888:8888"
api-gateway:
build: ./api-gateway
ports:
- "8080:8080"
depends_on:
- eureka-server
- config-server
user-service:
build: ./user-service
depends_on:
- eureka-server
- config-server
order-service:
build: ./order-service
depends_on:
- eureka-server
- config-server

Start with:

start.sh
docker-compose up --build

Common Mistakes to Avoid

I made all of these. Learn from my failures:

MistakeConsequenceFix
Skipping Spring Boot basicsCan’t troubleshoot auto-configuration issuesLearn IoC, DI, auto-config first
Learning components in isolationDon’t understand how they work togetherBuild a complete system progressively
Ignoring testingMicroservices are harder to debugLearn integration testing, contract testing
Skipping containerizationDeployment becomes painfulLearn Docker from the start
Following outdated tutorialsLearn deprecated Netflix OSSCheck Spring Cloud version compatibility
No fallback methodsSilent failures, poor user experienceAlways implement graceful degradation

How This Path Solves the Original Problems

Complexity: We introduce components one at a time, each building on the previous.

Fragmented resources: This single path covers what you need, in the right order.

Rapid evolution: The components here (Eureka, Gateway, Config, Resilience4j) are current and actively maintained.

Theory-practice gap: Each step includes working code. Don’t just read—build it.

When Are You Ready to Move On?

You understand Spring Cloud basics when you can:

  • Explain WHY service discovery is needed (not just HOW to configure Eureka)
  • Implement a circuit breaker with fallback from scratch
  • Configure routing rules in Spring Cloud Gateway
  • Set up a Config Server with Git backend
  • Deploy multiple services with Docker Compose
  • Debug when a service can’t register with Eureka

Red flags (keep practicing):

  • Can’t build a microservices project without following a tutorial
  • Don’t understand what lb:// means in gateway routes
  • Never configured fallback methods for circuit breakers
  • Don’t know the difference between client-side and server-side discovery

Summary

In this post, I showed a 6-step path to learn Spring Cloud microservices from scratch. The key insight: learn components in the order you’d implement them—discovery first, then gateway, then config, then resilience.

Start with a Eureka server and one microservice. Add a second service. Then gateway. Then config. Then resilience patterns. This mirrors real-world implementation and builds practical skills efficiently.

The hardest part isn’t the technology—it’s knowing what to learn first and how pieces fit together. Now you have that map.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments