Cloud Native 10 min read

How OpenFeign and Spring Cloud LoadBalancer Work Together: Deep Source Code Walkthrough

This article provides a detailed source‑code analysis of how OpenFeign and Spring Cloud LoadBalancer collaborate in Spring Cloud microservices, covering core roles, the full request‑response chain, configuration, extension points, reactive vs blocking behavior, performance tuning, and a comparison with Ribbon.

Ray's Galactic Tech
Ray's Galactic Tech
Ray's Galactic Tech
How OpenFeign and Spring Cloud LoadBalancer Work Together: Deep Source Code Walkthrough

Introduction

In a microservice architecture, service invocation is a core capability. Spring Cloud provides OpenFeign as a declarative HTTP client and Spring Cloud LoadBalancer as a client‑side load‑balancing framework. Together they separate the concerns of building HTTP requests (Feign) and selecting a concrete service instance (LoadBalancer).

Core Roles

OpenFeign : Generates a dynamic proxy from an interface annotated with @FeignClient. The proxy builds RequestTemplate objects, sends HTTP requests, and decodes responses.

Spring Cloud LoadBalancer : Replaces Ribbon. It obtains service instances from a discovery client (Eureka, Consul, Nacos, etc.) and selects one according to a strategy (round‑robin, random, or custom). It rewrites the service‑name URL to a concrete IP:Port before the request is executed.

Source‑Code Call Chain Overview

A typical call such as userFeignClient.getUser(1) follows these steps:

1. Feign Dynamic Proxy Creation

Enable scanning with @EnableFeignClients. FeignClientsRegistrar scans for @FeignClient interfaces. FeignClientFactoryBean creates a FeignInvocationHandler proxy.

The proxy implements InvocationHandler.invoke and dispatches each method to a MethodHandler.

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return dispatch.get(method).invoke(args); // dispatches to the concrete MethodHandler
}

2. Building the Request – RequestTemplate

SynchronousMethodHandler

parses method annotations ( @RequestMapping, @PathVariable, etc.) and creates a RequestTemplate.

The template still contains the logical service name, e.g. http://user-service/api/users/1.

3. LoadBalancer Intervenes – LoadBalancerFeignClient

Spring Cloud replaces Feign’s default Client with LoadBalancerFeignClient:

@Override
public Response execute(Request request, Options options) throws IOException {
    URI originalUri = URI.create(request.url());
    String serviceName = originalUri.getHost();
    // Choose an instance via LoadBalancer
    ServiceInstance instance = loadBalancerClient.choose(serviceName);
    // Reconstruct URL: service name → IP:Port
    URI newUri = loadBalancerClient.reconstructURI(instance, originalUri);
    Request newRequest = Request.create(request.httpMethod(), newUri.toString(), request.headers(), request.body(), request.charset());
    return delegate.execute(newRequest, options); // delegate to the underlying HTTP client
}

The service name is replaced with a concrete address, and the request is handed to the underlying HTTP client.

4. LoadBalancer Instance Selection

Interface: LoadBalancerClient (or ReactorServiceInstanceLoadBalancer for reactive mode).

Steps:

Obtain the list of instances from ServiceInstanceListSupplier (backed by Nacos, Consul, Eureka, etc.).

Select an instance according to the configured strategy.

Return the chosen ServiceInstance.

Round‑robin implementation example ( RoundRobinLoadBalancer):

int pos = position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = instances.get(pos % instances.size());

5. Response Decoding

Decoder : Default ResponseEntityDecoder uses Spring MVC HttpMessageConverters to convert JSON payloads to Java objects.

ErrorDecoder : Transforms HTTP error statuses into application‑specific exceptions.

Assembly and Extension Mechanisms

Auto‑Configuration : FeignAutoConfiguration wires a Client. If a LoadBalancerClient bean is present, it injects LoadBalancerFeignClient; otherwise it falls back to Client.Default.

Contract : SpringMvcContract parses Spring MVC annotations ( @GetMapping, @RequestParam, etc.) and produces the RequestTemplate.

RequestInterceptor : Allows adding headers, tokens, or trace IDs (e.g., for Zipkin/Jaeger) to every request.

Fault Tolerance :

Feign retry via Retryer (default limited retries, customizable).

LoadBalancer retry integrates with Spring Retry to retry instance‑selection failures.

Often combined with Resilience4j for circuit‑breaking, rate‑limiting, and bulkhead isolation.

Reactive vs Blocking Differences

Feign operates on a synchronous, blocking model.

LoadBalancer core is reactive ( ReactorServiceInstanceLoadBalancer). BlockingLoadBalancerClient provides a blocking wrapper for Feign and RestTemplate.

Fully non‑blocking calls can be built with WebClient + LoadBalancer.

Production Practices and Tuning

Replace Underlying HTTP Client

Default HttpURLConnection is unsuitable for high concurrency.

Recommended alternatives: OkHttp or Apache HttpClient.

Enable via feign.okhttp.enabled=true or feign.httpclient.enabled=true.

Connection Pool and Timeouts

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 5000

Service Discovery Latency

Use CachingServiceInstanceListSupplier to cache instance lists and avoid frequent registry queries.

Configure an appropriate refresh interval to reduce failures caused by delayed deregistration.

Logging for Debugging logging.level.feign=DEBUG prints request details. logging.level.org.springframework.cloud.loadbalancer=TRACE prints the selected instance.

Comparison with Ribbon

Status : Ribbon is deprecated; Spring Cloud LoadBalancer is the recommended replacement.

API Model : Ribbon uses the Netflix API; LoadBalancer uses Spring‑native interfaces.

Sync/Reactive : Ribbon is synchronous only; LoadBalancer has a reactive core with a synchronous wrapper.

Extensibility : Ribbon is hard to extend; LoadBalancer is plug‑in and SPI‑based.

Spring Cloud Version : Ribbon is supported up to Hoxton; LoadBalancer is the default from Hoxton onward.

Key Takeaways

The call chain is: annotation parsing → dynamic proxy → request building → LoadBalancer instance selection → URL reconstruction → underlying HTTP client execution → response decoding.

Responsibility separation: Feign abstracts HTTP communication; LoadBalancer decides which service instance to call.

Extension points include RequestInterceptor, custom Decoder / ErrorDecoder, Retryer, and a custom ReactorServiceInstanceLoadBalancer.

LoadBalancer’s core is reactive, but a blocking client is provided for compatibility with Feign and RestTemplate.

Production optimizations: swap the HTTP client (OkHttp/Apache), tune connection timeouts, enable instance‑list caching, and integrate resilience libraries such as Resilience4j.

OpenFeign and LoadBalancer call chain diagram
OpenFeign and LoadBalancer call chain diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Microservicesload balancingsource-code-analysisSpring CloudOpenFeignSpring Cloud LoadBalancer
Ray's Galactic Tech
Written by

Ray's Galactic Tech

Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.