Cloud Native 6 min read

Master Spring Cloud LoadBalancer: Quick Start and Custom Strategies

This guide shows how to quickly integrate Spring Cloud LoadBalancer into a Spring Cloud 2020 project, configure built‑in round‑robin or random policies, create custom gray load‑balancing strategies, and streamline bean registration for advanced load‑balancing scenarios.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Master Spring Cloud LoadBalancer: Quick Start and Custom Strategies

How to use the heavily recommended load balancer Spring Cloud LoadBalancer (SCL) in Spring Cloud 2020 and extend load‑balancing strategies? This article provides the answers.

Quick Start SCL

If you want to use SCL in a project, simply add the following Maven dependency:

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
  &lt;artifactId&gt;spring-cloud-starter-loadbalancer&lt;/artifactId&gt;
&lt;/dependency&gt;
</code>

SCL builds on service discovery. Since Spring Cloud Alibaba does not yet support SCL (see compatibility solution in reference [1]), you can test with Eureka.

When combining RestTemplate with client‑side load balancing, add the

@LoadBalanced

annotation to the bean definition.

<code>@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}
</code>

Personalized Load‑Balancing Strategies

The current Spring Cloud 2020 version includes round‑robin and random strategies, with round‑robin as the default.

You can specify a service‑level strategy using the

LoadBalancerClient

annotation.

<code>@LoadBalancerClient(value = "demo-provider", configuration = RandomLoadbalancerConfig.class)
</code>
<code>public class RandomLoadbalancerConfig {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}
</code>

Custom Load‑Balancing Strategy

SCL supports fewer strategies than Ribbon, so developers can implement custom ones. Below is an example of a gray load‑balancing strategy based on registration‑center metadata.

Define the gray load‑balancing strategy:

<code>@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private String serviceId;

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next()
                .map(serviceInstances -> getInstanceResponse(serviceInstances, request));
    }

    Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {
        // No available instances, return empty response
        if (CollUtil.isEmpty(instances)) {
            log.warn("No instance available {}", serviceId);
            return new EmptyResponse();
        }

        DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
        RequestData clientRequest = (RequestData) requestContext.getClientRequest();
        HttpHeaders headers = clientRequest.getHeaders();

        String reqVersion = headers.getFirst(CommonConstants.VERSION);
        if (StrUtil.isBlank(reqVersion)) {
            return super.choose(request).block();
        }

        // Match instance metadata with version
        for (ServiceInstance instance : instances) {
            NacosServiceInstance nacosInstance = (NacosServiceInstance) instance;
            Map<String, String> metadata = nacosInstance.getMetadata();
            String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION);
            if (reqVersion.equalsIgnoreCase(targetVersion)) {
                log.debug("gray request match success :{} {}", reqVersion, nacosInstance);
                return new DefaultResponse(nacosInstance);
            }
        }
        // Fallback to round‑robin
        return super.choose(request).block();
    }
}
</code>

Inject the gray strategy into the client:

<code>@LoadBalancerClient(value = "demo-provider", configuration = GrayRoundLoadbalancerConfig.class)
</code>

Define version number on service instances (illustrated below).

Test by sending a request with a version header:

<code>curl --location --request GET 'http://localhost:6060/req?key=b' \
--header 'VERSION: b'
</code>

Optimizing Load‑Balancing Strategy Injection

Manually injecting each custom strategy via

LoadBalancerClient

is cumbersome. You can follow the batch injection logic of

LoadBalancerClients

to create a custom BeanRegistrar.

<code>public class GrayLoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Field[] fields = ReflectUtil.getFields(ServiceNameConstants.class);

        // Iterate service names and inject gray load balancers
        for (Field field : fields) {
            Object fieldValue = ReflectUtil.getFieldValue(ServiceNameConstants.class, field);
            registerClientConfiguration(registry, fieldValue, GrayLoadBalancerClientConfiguration.class);
        }
    }
}
</code>

Reference

[1] Compatibility solution for Spring Cloud 2020: https://gitee.com/log4j/pig

JavaMicroservicesSpring CloudCustomizationload balancer
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

login 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.