Master Spring Cloud LoadBalancer: From RestTemplate to OpenFeign
This tutorial walks through replacing Ribbon with Spring Cloud LoadBalancer, showing how to configure dependencies, set up RestTemplate and OpenFeign clients, customize caching and request transformation, and verify load‑balanced calls using Nacos as the service registry.
LoadBalancer Introduction
LoadBalancer is the Spring Cloud official load‑balancing component that replaces Ribbon and is largely compatible with Ribbon’s usage.
Usage
Demonstrate basic usage with Nacos as the service registry, using
nacos-loadbalancer-serviceand
nacos-user-servicefor mutual calls.
Load Balancing
Use
RestTemplatewith
@LoadBalancedto achieve client‑side load balancing.
Add the
spring-cloud-starter-loadbalancerdependency to the
pom.xmlof
nacos-loadbalancer-service.
Create a Java configuration class that defines a
RestTemplatebean annotated with
@LoadBalanced.
Configure request timeout in
application.yml.
Call the remote service in a controller using the configured
RestTemplate.
<code><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency></code> <code>@Configuration
public class RestTemplateConfig {
@Bean
@ConfigurationProperties(prefix = "rest.template.config")
public HttpComponentsClientHttpRequestFactory customHttpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory();
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate(customHttpRequestFactory());
}
}</code> <code>rest:
template:
config:
connectTimeout: 5000
readTimeout: 5000</code> <code>@RestController
@RequestMapping("/user")
public class UserLoadBalancerController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String userServiceUrl;
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}
// other CRUD methods omitted for brevity
}</code>Declarative Service Call
OpenFeign can be used for declarative calls. Add the
spring-cloud-starter-openfeigndependency, define a Feign client interface, and invoke it from a controller.
<code><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency></code> <code>@FeignClient(value = "nacos-user-service")
public interface UserService {
@PostMapping("/user/create")
CommonResult create(@RequestBody User user);
@GetMapping("/user/{id}")
CommonResult<User> getUser(@PathVariable Long id);
@GetMapping("/user/getByUsername")
CommonResult<User> getByUsername(@RequestParam String username);
@PostMapping("/user/update")
CommonResult update(@RequestBody User user);
@PostMapping("/user/delete/{id}")
CommonResult delete(@PathVariable Long id);
}</code> <code>@RestController
@RequestMapping("/userFeign")
public class UserFeignController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return userService.getUser(id);
}
// other methods omitted for brevity
}</code>Feign timeout can be configured in
application.yml:
<code>feign:
client:
config:
default: # Feign call timeout configuration
connectTimeout: 5000
readTimeout: 5000</code>Service Instance Cache
LoadBalancer caches service instances locally to improve performance. The default cache TTL is 35 seconds; it can be customized.
<code>spring:
cloud:
loadbalancer:
cache:
enabled: true # enable cache
ttl: 5s # cache time‑to‑live
capacity: 256 # cache size</code>HTTP Request Transformation
To add custom headers to each request, implement a
LoadBalancerRequestTransformerbean that injects the service instance ID into the
X-InstanceIdheader.
<code>@Configuration
public class LoadBalancerConfig {
@Bean
public LoadBalancerRequestTransformer transformer() {
return new LoadBalancerRequestTransformer() {
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
return new HttpRequestWrapper(request) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = super.getHeaders();
headers.add("X-InstanceId", instance.getInstanceId());
return headers;
}
};
}
};
}
}</code>In the user service, retrieve and log the custom header:
<code>@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/{id}")
public CommonResult<User> getUser(@PathVariable Long id) {
User user = userService.getUser(id);
LOGGER.info("User name: {}", user.getUsername());
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String instanceId = request.getHeader("X-InstanceId");
if (StrUtil.isNotEmpty(instanceId)) {
LOGGER.info("Received custom header X-InstanceId={}", instanceId);
}
return new CommonResult<>(user);
}
}</code>Summary
Using Spring Cloud LoadBalancer provides a seamless migration path from Ribbon, with similar configuration and functionality while leveraging modern Spring Cloud features.
Reference
Official documentation: https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.