# Spring Cloud for Building Java Microservices: Architecture, Components, and Code Samples

> Learn to build Java microservices with Spring Cloud. Explore architecture, components, and code samples for service discovery, load balancing, and fault tolerance in cloud-native apps.

- Repository: [Doocs/advanced-java](https://github.com/doocs/advanced-java)
- Tags: architecture
- Published: 2026-02-28

---

**Spring Cloud provides a comprehensive suite of libraries that simplify the development of distributed, cloud-native Java applications by handling cross-cutting concerns like service discovery, load balancing, and fault tolerance.**

Spring Cloud extends **Spring Boot** to address common patterns in distributed systems, allowing developers to focus on business logic rather than infrastructure. The **doocs/advanced-java** repository offers detailed documentation and minimal code samples demonstrating how to assemble these components into production-ready microservices. This guide synthesizes those resources into a practical implementation reference.

## Service Registration and Discovery with Eureka

**Eureka** acts as the central registry in a Spring Cloud microservices architecture. As documented in [`docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md), services register themselves on startup and emit periodic heartbeats to maintain their status in the registry.

### Configuring the Eureka Server

To establish a registry, create a Spring Boot application with the **`@EnableEurekaServer`** annotation:

```java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

```

Add the server dependency to [`pom.xml`](https://github.com/doocs/advanced-java/blob/main/pom.xml):

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

```

### Registering Service Providers

Microservices identify themselves as Eureka clients using **`@EnableEurekaClient`**:

```java
@SpringBootApplication
@EnableEurekaClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

```

A simple REST controller exposes the service functionality:

```java
@RestController
@RequestMapping("/api")
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello from Provider";
    }
}

```

## Client-Side Load Balancing

After discovering service instances from Eureka, clients must select one instance to handle the request. The repository's technology stack documentation ([`docs/micro-services/micro-services-technology-stack.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-services-technology-stack.md)) identifies **Ribbon** as the historical solution, though modern Spring Cloud projects use **Spring Cloud LoadBalancer** as the lightweight, maintained alternative. Both implementations fetch the instance list from Eureka and apply algorithms like round-robin to distribute traffic.

## Inter-Service Communication with OpenFeign

**Feign** eliminates boilerplate HTTP client code by generating type-safe REST clients from Java interfaces. According to the technology stack guide, Feign integrates seamlessly with Ribbon or Spring Cloud LoadBalancer to provide client-side load balancing without explicit configuration.

Enable Feign scanning with **`@EnableFeignClients`**:

```java
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.example.consumer.feign")
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

```

Define the client interface using **`@FeignClient`** with the logical service name registered in Eureka:

```java
@FeignClient(name = "provider-service")
public interface HelloClient {
    @GetMapping("/api/hello")
    String hello();
}

```

Inject and use the client in a controller:

```java
@RestController
@RequestMapping("/consumer")
@RequiredArgsConstructor
public class ConsumerController {
    private final HelloClient helloClient;

    @GetMapping("/greet")
    public String greet() {
        return helloClient.hello();
    }
}

```

Dependency configuration:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

```

## Fault Tolerance and Circuit Breaking

To prevent cascading failures, Spring Cloud integrates circuit breaker patterns. The repository documents **Hystrix** extensively, though notes that since Spring Cloud 2020, it exists in maintenance mode with **Sentinel** or **Resilience4j** recommended as successors.

Implement a fallback using Hystrix:

```java
@FeignClient(name = "provider-service", fallback = HelloClientFallback.class)
public interface HelloClient {
    @GetMapping("/api/hello")
    String hello();
}

@Component
class HelloClientFallback implements HelloClient {
    @Override
    public String hello() {
        return "Fallback response – provider is unavailable";
    }
}

```

The comparison in [`docs/high-availability/sentinel-vs-hystrix.md`](https://github.com/doocs/advanced-java/blob/main/docs/high-availability/sentinel-vs-hystrix.md) details how Sentinel adds adaptive flow control and rate limiting beyond Hystrix's thread-pool isolation model.

## Distributed Configuration Management

**Spring Cloud Config** centralizes configuration files (YAML/Properties) in a Git repository or local filesystem, serving them to all microservices via a dedicated server. The governance documentation ([`docs/micro-services/micro-service-governance.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-service-governance.md)) also lists **Apollo** as an alternative for production-grade configuration management.

Bootstrap a service to fetch external configuration:

```yaml
spring:
  application:
    name: provider-service
  cloud:
    config:
      uri: http://config-server:8888
      failFast: true

```

The Config Server itself requires **`@EnableConfigServer`** and the following dependency:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

```

## API Gateway with Zuul

**Zuul** (documented in the technology stack) serves as the single entry point for client requests, handling dynamic routing, authentication, and request transformation. While the repository covers Zuul 1.x via **`@EnableZuulProxy`**, modern implementations should consider migrating to **Spring Cloud Gateway** for non-blocking I/O performance.

Gateway application setup:

```java
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

```

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

```

## Security and Observability

The governance document ([`docs/micro-services/micro-service-governance.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-service-governance.md)) enumerates **Spring Security** and **OAuth** for handling authentication and authorization across service boundaries. For distributed tracing, the technology stack includes **Zipkin** and **Brave** to visualize request flows across the microservice ecosystem.

## Complete Microservice Lifecycle

According to the architectural documentation in **doocs/advanced-java**, these components cooperate in a defined lifecycle:

1. **Bootstrap** – Spring Boot applications initialize with `spring-cloud-starter` dependencies.
2. **Registration** – Services annotate with `@EnableEurekaClient` to register with the Eureka registry on startup.
3. **Discovery** – Feign clients resolve logical names to physical instances via the load balancer.
4. **Resilience** – Hystrix or Sentinel wraps calls with circuit breaker logic and fallback execution.
5. **Configuration** – Services fetch environment-specific properties from the Config Server at runtime.
6. **Routing** – Zuul or Spring Cloud Gateway applies security filters and routes requests to downstream services.
7. **Tracing** – Zipkin collects span data for end-to-end request visualization.

## Summary

- **Eureka** ([`docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md)) provides the service registry using `@EnableEurekaServer` and `@EnableEurekaClient`.
- **Feign** simplifies HTTP communication with declarative interfaces annotated with `@FeignClient`.
- **Spring Cloud LoadBalancer** replaces Ribbon for client-side load distribution across discovered instances.
- **Hystrix** and **Sentinel** ([`docs/high-availability/sentinel-vs-hystrix.md`](https://github.com/doocs/advanced-java/blob/main/docs/high-availability/sentinel-vs-hystrix.md)) implement circuit breakers to prevent system cascade failures.
- **Spring Cloud Config** centralizes configuration management, supporting dynamic refresh without service restarts.
- **Zuul** (documented in [`docs/micro-services/micro-services-technology-stack.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-services-technology-stack.md)) acts as the API gateway for routing and cross-cutting concerns.

## Frequently Asked Questions

### How does Eureka handle service registration and heartbeats?

Eureka clients register on startup by posting metadata to the Eureka Server, then emit periodic heartbeat renewals every 30 seconds (configurable) to maintain their "UP" status. If a client fails to renew within a configured threshold, the server evicts the instance. This lifecycle is detailed in [`docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md), which covers the self-preservation mode that prevents mass eviction during network partitions.

### What is the difference between Ribbon and Spring Cloud LoadBalancer?

**Ribbon** was the original client-side load balancer integrated with Eureka and Feign, as noted in [`docs/micro-services/micro-services-technology-stack.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-services-technology-stack.md). However, it entered maintenance mode. **Spring Cloud LoadBalancer** is the modern, lightweight replacement that ships with Spring Cloud 2020+ releases, providing reactive support and eliminating the need for external Netflix dependencies while maintaining the same round-robin and random selection algorithms.

### How does Spring Cloud Config enable dynamic configuration changes?

Services bootstrap with a [`bootstrap.yml`](https://github.com/doocs/advanced-java/blob/main/bootstrap.yml) pointing to a Config Server URI (`http://config-server:8888`). The Config Server (`@EnableConfigServer`) exposes configuration files stored in a Git repository. While the repository notes support for dynamic refresh, production environments often pair this with **Spring Cloud Bus** (not explicitly detailed in the source but implied by "dynamic refresh") or **Apollo** (listed in [`docs/micro-services/micro-service-governance.md`](https://github.com/doocs/advanced-java/blob/main/docs/micro-services/micro-service-governance.md)) to push configuration updates to running instances without requiring restarts.

### Why would I choose Sentinel over Hystrix for circuit breaking?

As analyzed in [`docs/high-availability/sentinel-vs-hystrix.md`](https://github.com/doocs/advanced-java/blob/main/docs/high-availability/sentinel-vs-hystrix.md), **Sentinel** offers flow control, concurrency limiting, and circuit breaking in a single library with a dedicated dashboard, whereas **Hystrix** focuses primarily on thread isolation and fallbacks. Sentinel supports adaptive traffic shaping and QPS-based limiting, making it more suitable for high-availability scenarios in modern cloud-native deployments where Hystrix's maintenance status makes it a legacy choice.