skip to content

What is Spring Cloud LoadBalancer and what does the @LoadBalanced annotation do?

level: juniorimportance: must knowfreq 55%

answer

  1. client-side, replaces Ribbon
  2. @LoadBalanced = qualifier -> interceptor/filter
  3. host = logical service id, not DNS
  4. discovery -> pick instance -> rewrite URL
  5. spring-cloud-starter-loadbalancer

basics

~10 s

Spring Cloud LoadBalancer is a client-side load balancer that replaced Netflix Ribbon. @LoadBalanced marks a RestTemplate or WebClient.Builder so URLs using a logical service name resolve to a real instance, spreading calls across instances.

solid answer

~40 s

Spring Cloud LoadBalancer (SCLB) is Spring's built-in client-side load balancer, the successor to the now-removed Netflix Ribbon. It ships in spring-cloud-starter-loadbalancer and picks a target instance in the caller, not via a proxy. You annotate a RestTemplate or WebClient.Builder bean with @LoadBalanced. That tells Spring to attach a load-balancing interceptor/filter, so when you call http://order-service/orders/1, 'order-service' is treated as a logical service id (not a DNS host). SCLB asks the discovery client for instances of that service, picks one (round-robin by default), and rewrites the URL to that instance's host:port. This gives you client-side balancing plus resilience: if instances scale up/down, callers adapt without config changes. Without @LoadBalanced, the same URL fails because 'order-service' isn't a resolvable hostname.

code

java · 20 lines
java
@Configuration
class AppConfig {
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
class OrderClient {
    private final RestTemplate rt;
    OrderClient(RestTemplate rt) { this.rt = rt; }

    Order fetch(long id) {
        // "order-service" is a logical service id resolved by SCLB,
        // NOT a DNS hostname. Without @LoadBalanced this throws UnknownHostException.
        return rt.getForObject("http://order-service/orders/{id}", Order.class, id);
    }
}

go deeper

for a junior

Know it's client-side, replaces Ribbon, and @LoadBalanced lets you call services by name.

for a middle

Explain that the annotation adds an interceptor/filter and the host is a discovery service id.

for a senior

Connect @LoadBalanced to LoadBalancerClientFactory, ServiceInstanceListSupplier, and discovery.

for a principal

Discuss when client-side LB is the wrong choice (mesh/gateway already balancing) and the trade-offs of in-process balancing.

**The problem it solves.** In microservices, a service like `order-service` runs as many instances behind no single fixed address. A caller needs to (a) discover the current set of instances and (b) choose one per request. Spring Cloud LoadBalancer (SCLB) does both in the *client* process — hence *client-side* load balancing — rather than routing through a dedicated load-balancer/proxy. **Replacing Ribbon.** SCLB is the official replacement for **Netflix Ribbon**, which is deprecated and removed from current Spring Cloud. If you see `@RibbonClient`, `IRule`, or `ribbon.*` properties, that's the legacy world; the modern equivalents are `@LoadBalancerClient`, `ReactorLoadBalancer`, and `spring.cloud.loadbalancer.*`. **How @LoadBalanced wires in.** `@LoadBalanced` is a Spring `@Qualifier`. You put it on a bean: ```java @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } ``` SCLB's auto-configuration collects every `@LoadBalanced RestTemplate` and adds a `LoadBalancerInterceptor` (or `RetryLoadBalancerInterceptor` when retries are on) to it. For reactive clients you annotate a `WebClient.Builder`; SCLB adds a `ReactorLoadBalancerExchangeFilterFunction`. **What happens per request.** You call a URL whose host is a **logical service id**, e.g. `http://order-service/orders/1`. The interceptor/filter: 1. Extracts `order-service` as the service id. 2. Uses the `ReactiveLoadBalancer.Factory` (`LoadBalancerClientFactory`) to get that service's `ReactorLoadBalancer`. 3. The load balancer asks a `ServiceInstanceListSupplier` for the current instances (typically from a `DiscoveryClient` — Eureka, Consul, Kubernetes, etc.). 4. It picks one instance (default: round-robin). 5. The URL is rewritten to the chosen instance's real `host:port`, then the request proceeds. **Why the URL must use a service name.** `order-service` is not a DNS name; it's a key into discovery. Without `@LoadBalanced`, the plain `RestTemplate` tries to open a socket to host `order-service` and fails with UnknownHost. The annotation is what turns that pseudo-host into a discovery lookup. **Gotchas.** - You need `spring-cloud-starter-loadbalancer` on the classpath and usually a discovery client. In some starters (like the Eureka client) SCLB is pulled in transitively. - `@LoadBalanced` belongs on the *builder/template bean*, not on the calling method. - A non-annotated `RestTemplate` and a `@LoadBalanced` one can coexist; inject the one you need (use qualifiers). **When to use.** Any time a service calls another service by logical name and you want in-process balancing without a sidecar/proxy. If you already front everything with a service mesh (Istio/Linkerd) or an API gateway doing the balancing, client-side LB may be redundant.

  • What happens if you forget @LoadBalanced but still call http://order-service/...?
    The plain RestTemplate/WebClient treats 'order-service' as a hostname and fails to resolve it (UnknownHostException), because nothing intercepts the request to translate the service id into a real instance.
  • Is Spring Cloud LoadBalancer a server-side load balancer like nginx?
    No. It's client-side: the choosing logic runs inside the caller's JVM, per request. There's no separate proxy hop; the caller talks directly to the chosen instance.

saying these in an interview costs you the question

  • Thinking @LoadBalanced makes it server-side / a proxy
  • Believing 'order-service' is resolved by DNS rather than discovery
  • Saying Ribbon is still the default (it's removed)
  • Putting @LoadBalanced on the controller/method instead of the bean

context