在 Spring Cloud LoadBalancer 中,LoadBalancerRequest 作为一个函数式接口,主要作用是封装需要在负载均衡选中的服务实例上执行的请求逻辑。它充当了负载均衡选择(由 LoadBalancerClient 负责)与实际服务调用(例如 HTTP 请求)之间的桥梁,不仅承载核心调用逻辑,还支持在请求执行前后嵌入自定义处理(如日志记录、metrics 指标统计、失败重试等增强功能)。
当 LoadBalancerClient 在选中实例后,将触发执行 LoadBalancerRequest 。LoadBalancerRequest 将作为“请求执行的载体”,封装了针对服务实例的具体调用逻辑(如发送 HTTP 请求、处理响应)。
LoadBalancerRequest 实现了“负载均衡选择”与“执行请求” 逻辑解耦,这使负载均衡客户端(LoadBalancerClient)无需关心请求的具体内容,只需专注于实例选择和调用触发。
📢 注意:LoadBalancerRequest 需要配合 LoadBalancerClient.execute(...) 方法使用,适用于所有需要通过负载均衡调用服务的场景(如 RestTemplate、自定义服务调用等)。
LoadBalancerRequest 接口仅定义一个核心方法 apply(),用于在指定实例上执行 HTTP 请求。代码如下:
package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
public interface LoadBalancerRequest<T> {
/**
* 对选中的服务实例执行实际的HTTP请求操作,并返回结果。
*
* 该方法由 LoadBalancerClient 在完成服务实例选择后调用,参数为负载均衡器选中的服务实例(ServiceInstance),
* 开发者可在此方法中实现具体的服务调用逻辑(如 HTTP 请求、RPC 调用等),同时可嵌入前置/后置处理逻辑。
*
* @param instance 负载均衡器选中的服务实例,包含服务的主机、端口等连接信息
* @return 服务调用的响应结果,类型为泛型 T
* @throws Exception 执行请求过程中可能抛出的异常(如连接超时、服务不可用等)
*/
T apply(ServiceInstance instance) throws Exception;
}注意,LoadBalancerRequest 通常与 LoadBalancerClient 配合使用,完整流程如下:
(1)开发者通过 lambda 或匿名类定义 LoadBalancerRequest,封装具体的请求逻辑(如使用 RestTemplate 发送 HTTP 请求)。
(2)调用 LoadBalancerClient.execute(serviceId, request) 方法,触发负载均衡流程:
LoadBalancerClient 先通过负载均衡策略选择一个服务实例(调用 choose(serviceId))。
接着调用 request.apply(instance),在选中的实例上执行请求逻辑。
(3)获取 apply 方法的返回值,即请求结果。
注意:这里不需要使用 @LoadBalanced 去修饰 RestTemplate,直接创建一个 RestTemplate 即可。
下面代码展示了如何通过 LoadBalancerRequest 配合 LoadBalancerClient 实现负载均衡调用。
代码如下:
package com.hxstrive.springcloud.loadbalancer_demo.demo3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
@SpringBootApplication
@EnableDiscoveryClient
public class LoadbalancerDemoApplication implements CommandLineRunner {
// 注入 LoadBalancerClient 实例
@Autowired
private LoadBalancerClient loadBalancerClient;
public static void main(String[] args) {
SpringApplication.run(LoadbalancerDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient@5c40498b
System.out.println(loadBalancerClient);
// 服务名称
final String serviceId = "USER-SERVICE";
// 目标接口地址,主机部分为服务名,而非实际IP地址
final URI originalUri = URI.create("http://" + serviceId + "/api/users");
// 通过 LoadBalancerClient 调用服务
String result = loadBalancerClient.execute(serviceId, new LoadBalancerRequest<String>() {
// 发起请求
// instance 为 LoadBalancerClient 通过负载均衡算法获取到的服务实例
@Override
public String apply(ServiceInstance instance) throws Exception {
// LoadBalancerUriTools.reconstructURI() 工具方法用于将服务地址中的服务名替换为实际的IP地址
String url = LoadBalancerUriTools.reconstructURI(instance, originalUri).toString();
return new RestTemplate().getForObject(url, String.class);
}
});
System.out.println(result);
}
}注意:上述代码实现了 CommandLineRunner 接口,应用启动成功后自动执行 run(String... args) 方法,避免为了测试去创建一个控制器,通过浏览器访问,这样可以快速验证一些问题。
代码通过创建一个匿名 LoadBalancerRequest 内部类封装“根据实例地址发送 HTTP 请求” 的逻辑,loadBalancerClient.execute() 负责选择实例并触发执行。这样就不需要手动指定实例地址,由负载均衡器自动选择,实现了服务调用的负载均衡透明化。
通过@LoadBalanced 注解修饰的 RestTemplate,其内部也是通过 LoadBalancerRequest 封装 HTTP 请求,由 LoadBalancerClient 完成实例选择和具体调用。
这样就避免我们自己去实现 LoadBalancerRequest,封装 HTTP 实际请求逻辑,开发就非常便捷。例如:
package com.hxstrive.springcloud.loadbalancer_demo.demo2.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
// 注入 RestTemplate,并添加 @LoadBalanced 注解启用负载均衡
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}LoadBalancerClient 的 execute() 方法的核心逻辑就是调用 LoadBalancerRequest.apply(instance),是连接实例选择与请求执行的关键。
如下图,LoadBalancerClient 通过调用 apply() 发起实际 HTTP 调用:

更多细节可以分析源码。
除了与 RestTemplate 和 LoadBalancerClient 集成,还可通过 LoadBalancerRequestTransformer 对 LoadBalancerRequest 进行增强(如添加请求头、日志记录),实现请求的预处理。
LoadBalancerRequestTransformer 是一个用于对负载均衡均衡请求进行预处理转换的接口,主要作用是在请求发送到目标服务实例之前,对请求的元数据(如请求头、请求参数等)进行自定义修改或增强,以满足特定业务场景需求。
LoadBalancerRequestTransformer 接口定义如下:
package org.springframework.cloud.client.loadbalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpRequest;
/**
* 负载均衡请求转换器,用于在请求发送到目标服务实例前对 HTTP 请求进行自定义转换。
* 支持基于目标服务实例的信息(如元数据、地址等)动态修改请求内容,如添加请求头、调整路径等。
*
* @Order(0) 注解指定了默认的执行顺序为0,多个转换器可通过调整Order值控制执行先后(值越小越先执行)
*/
@Order(0)
public interface LoadBalancerRequestTransformer {
/**
* 转换器的默认执行顺序,值为0
*/
int DEFAULT_ORDER = 0;
/**
* 对HTTP请求进行转换,可基于目标服务实例的信息定制请求内容。
*
* @param request 原始的HTTP请求对象(包含请求头、方法、URI等信息)
* @param instance 经过负载均衡选择的目标服务实例(可从中获取服务ID、主机、端口、元数据等)
* @return 转换后的HTTP请求对象,将被用于实际发送到目标服务实例
*/
HttpRequest transformRequest(HttpRequest request, ServiceInstance instance);
}(1)统一添加请求头:为所有经过负载均衡的请求添加 X-LoadBalancer-Service 头,标识目标服务名。
package com.hxstrive.springcloud.loadbalancer_demo.demo4.transformer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestTransformer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.support.HttpRequestWrapper;
import org.springframework.stereotype.Component;
@Component
public class ServiceHeaderTransformer implements LoadBalancerRequestTransformer {
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
// 基于目标服务实例的信息构建自定义请求头
final HttpHeaders headers = new HttpHeaders();
headers.putAll(request.getHeaders());
headers.add("X-LoadBalancer-Service", instance.getServiceId()); // 添加服务名头
// 返回包装了新请求头的 HttpRequest
return new HttpRequestWrapper(request) {
@Override
public HttpHeaders getHeaders() {
System.out.println("->> headers=" + headers);
return headers;
}
};
}
}(2)根据实例元数据调整请求:若服务实例的元数据中包含 version 信息,可动态修改请求路径适配版本。
package com.hxstrive.springcloud.loadbalancer_demo.demo4.transformer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestTransformer;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.support.HttpRequestWrapper;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
@Component
public class VersionPathTransformer implements LoadBalancerRequestTransformer {
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
// 从服务实例元数据中获取版本信息
String version = instance.getMetadata().getOrDefault("version", "v1");
// 原始请求路径(如 /api/user)
String originalPath = request.getURI().getPath();
// 拼接版本路径(如 /v2/api/user)
String newPath = "/" + version + originalPath;
// 构建新的 URI 并包装请求
final URI newUri = UriComponentsBuilder.fromUri(request.getURI())
.path(newPath)
.build()
.toUri();
return new HttpRequestWrapper(request) {
@Override
public URI getURI() {
System.out.println("->> newUri=" + newUri);
return request.getURI(); // 为了能顺利调用,不返回 newUri
}
};
}
}💥注意,LoadBalancerRequestTransformer 通常通过以下方式生效:
(1)将自定义 LoadBalancerRequestTransformer 注册为 Spring 容器中的 Bean。
(2)负载均衡框架会自动发现这些转换器,并在请求执行前(LoadBalancerRequest.apply 阶段)按顺序调用它们的 transformRequest 方法。
(3)转换后的请求会被发送到目标服务实例。
编写完自己的 LoadBalancerRequestTransformer 后,可以在启动项目的 main() 方法打印出来,看看是否注册,如下:
package com.hxstrive.springcloud.loadbalancer_demo.demo4;
//...
@RestController
@SpringBootApplication
@EnableDiscoveryClient
public class LoadbalancerDemoApplication {
@Autowired
private RestTemplate restTemplate;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(LoadbalancerDemoApplication.class, args);
// 打印所有已加载的转换器
Map<String, LoadBalancerRequestTransformer> transformers = context.getBeansOfType(LoadBalancerRequestTransformer.class);
System.out.println("Loaded transformers: " + transformers.keySet());
}
@GetMapping("/getData")
public String getData() throws Exception {
// 关键:用服务名代替具体 IP:端口,LoadBalancer 会自动处理
String url = "http://USER-SERVICE/api/users"; // 服务名与提供者的 spring.application.name 一致
return restTemplate.getForObject(url, String.class);
}
}启动应用程序将输出如下信息:
Loaded transformers: [serviceHeaderTransformer, versionPathTransformer, loadBalancerServiceInstanceCookieTransformer, xForwarderHeadersTransformer]
继续访问 http://localhost:8080/getData 地址,输出信息如下:
->> ServiceHeaderTransformer#transformRequest() ->> VersionPathTransformer#transformRequest() ->> newUri=http://localhost:7003/api/users/v1/api/users ->> headers=[Accept:"text/plain, application/json, application/*+json, */*", Content-Length:"0", X-LoadBalancer-Service:"USER-SERVICE"]
根据输出得知,请求确实被修改了。
LoadBalancerRequest 是 Spring Cloud LoadBalancer 中封装请求执行逻辑的核心接口,通过函数式设计简化了“选中实例后执行请求”的流程。它与 LoadBalancerClient 协同工作,使开发者无需关心实例选择细节,只需专注于具体的服务调用逻辑,同时支持通过转换器(LoadBalancerRequestTransformer)进行请求增强,灵活满足日志、追踪、认证等附加需求。
注意:在实际开发中,LoadBalancerRequest 通常由框架自动创建(如 @LoadBalanced RestTemplate),但了解其原理有助于理解负载均衡的执行链路和自定义扩展。