源码
LoadBalanced
@LoadBalanced
注解用于标记 RestTemplate
、RestClient.Builder
或 WebClient.Builder
Bean,使其自动集成负载均衡客户端,实现在请求时自动通过负载均衡器选择服务实例。
java
// LoadBalancerRestClientBuilderBeanPostProcessor
// LoadBalancerWebClientBuilderBeanPostProcessor
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {}
LoadBalancerAutoConfiguration
java
@AutoConfiguration
@Conditional(BlockingRestClassesPresentCondition.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
public class LoadBalancerAutoConfiguration {
// 被标记为 @LoadBalanced 的 RestTemplate,会被注入到 restTemplates 变量中
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : restTemplates) {
// LoadBalancerInterceptorConfig.restTemplateCustomizer:
// LoadBalancerInterceptor
// RetryInterceptorAutoConfiguration.restTemplateCustomizer:
// RetryLoadBalancerInterceptor
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
// DeferringLoadBalancerInterceptorConfig
// LoadBalancerInterceptorConfig
// RetryInterceptorAutoConfiguration
}
java
@AutoConfiguration
static class DeferringLoadBalancerInterceptorConfig {
@Bean
@ConditionalOnMissingBean
public DeferringLoadBalancerInterceptor deferringLoadBalancerInterceptor(
ObjectProvider<BlockingLoadBalancerInterceptor> loadBalancerInterceptorObjectProvider) {
return new DeferringLoadBalancerInterceptor(loadBalancerInterceptorObjectProvider);
}
@Bean
@ConditionalOnBean(DeferringLoadBalancerInterceptor.class)
@ConditionalOnMissingBean
LoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor(
DeferringLoadBalancerInterceptor loadBalancerInterceptor, ApplicationContext context) {
return new LoadBalancerRestClientBuilderBeanPostProcessor(loadBalancerInterceptor, context);
}
}
java
@AutoConfiguration
@Conditional(RetryMissingOrDisabledCondition.class)
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
private static class RetryMissingOrDisabledCondition extends AnyNestedCondition {
RetryMissingOrDisabledCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class RetryTemplateMissing {
}
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "false")
static class RetryDisabled {
}
}
java
/**
* Auto configuration for retry mechanism.
*/
@AutoConfiguration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
}
/**
* Auto configuration for retry intercepting mechanism.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RetryTemplate.class)
@ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", matchIfMissing = true)
public static class RetryInterceptorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory,
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
return new RetryLoadBalancerInterceptor(loadBalancerClient, requestFactory, loadBalancedRetryFactory,
loadBalancerFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
LoadBalancerClient
@LoadBalancerClient
注解用于配置一个负载均衡客户端,通常应用于 @Configuration
类中,结合 LoadBalancerClientFactory
可获取配置的负载均衡客户端。它允许指定客户端名称、配置类等自定义负载均衡行为。
java
@Configuration(proxyBeanMethods = false)
@Import(LoadBalancerClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
/**
* A custom <code>@Configuration</code> for the load balancer client. Can contain
* override <code>@Bean</code> definition for the pieces that make up the client.
*
* @see LoadBalancerClientConfiguration for the defaults
* @return configuration classes for the load balancer client.
*/
Class<?>[] configuration() default {};
}
LoadBalancerClientConfigurationRegistrar
LoadBalancerClientConfigurationRegistrar
是一个 ImportBeanDefinitionRegistrar
实现,用于根据 @LoadBalancerClient
注解配置负载均衡客户端,并将相应的客户端配置注册到 Spring 上下文中。
java
public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
private static String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
String value = (String) client.get("value");
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
if (StringUtils.hasText(value)) {
return value;
}
throw new IllegalStateException("Either 'name' or 'value' must be provided in @LoadBalancerClient");
}
private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(LoadBalancerClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName());
if (attrs != null && attrs.containsKey("value")) {
AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
for (AnnotationAttributes client : clients) {
registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
}
}
if (attrs != null && attrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));
}
Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName());
String name = getClientName(client);
if (name != null) {
registerClientConfiguration(registry, name, client.get("configuration"));
}
}
}
LoadBalancerClientFactory
LoadBalancerClientFactory
是一个工厂类,用于根据不同服务 ID 创建子容器,管理客户端和负载均衡器的实例。
java
public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification> implements ReactiveLoadBalancer.Factory<ServiceInstance> {
private static final Log log = LogFactory.getLog(LoadBalancerClientFactory.class);
public static final String NAMESPACE = "loadbalancer";
public static final String PROPERTY_NAME = NAMESPACE + ".client.name";
private final LoadBalancerClientsProperties properties;
public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME, new HashMap<>());
this.properties = properties;
}
public LoadBalancerClientFactory(LoadBalancerClientsProperties properties, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME, applicationContextInitializers);
this.properties = properties;
}
public static String getName(Environment environment) {
return environment.getProperty(PROPERTY_NAME);
}
@Override
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
}
@Override
public LoadBalancerProperties getProperties(String serviceId) {
if (properties == null) {
if (log.isWarnEnabled()) {
log.warn("LoadBalancerClientsProperties is null. Please use the new constructor.");
}
return null;
}
if (serviceId == null || !properties.getClients().containsKey(serviceId)) {
// no specific client properties, return default
return properties;
}
// because specifics are overlayed on top of defaults, everything in `properties`,
// unless overridden, is in `clientsProperties`
return properties.getClients().get(serviceId);
}
@SuppressWarnings("unchecked")
public LoadBalancerClientFactory withApplicationContextInitializers(Map<String, Object> applicationContextInitializers) {
Map<String, ApplicationContextInitializer<GenericApplicationContext>> convertedInitializers = new HashMap<>();
applicationContextInitializers.keySet()
.forEach(contextId -> convertedInitializers.put(contextId,
(ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers
.get(contextId)));
return new LoadBalancerClientFactory(properties, convertedInitializers);
}
}
LoadBalancerAutoConfiguration
LoadBalancerAutoConfiguration
是 Spring Cloud LoadBalancer 的自动配置类,它提供了负载均衡相关的默认 Bean 配置,包括 LoadBalancerClientFactory
、LoadBalancerZoneConfig
和 LoadBalancerEagerContextInitializer
,并根据配置条件自动启用负载均衡功能。
java
@Configuration(proxyBeanMethods = false)
@LoadBalancerClients
@EnableConfigurationProperties({ LoadBalancerClientsProperties.class, LoadBalancerEagerLoadProperties.class })
@AutoConfigureBefore({ ReactorLoadBalancerClientAutoConfiguration.class, LoadBalancerBeanPostProcessorAutoConfiguration.class })
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.enabled", havingValue = "true", matchIfMissing = true)
public class LoadBalancerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancerZoneConfig zoneConfig(Environment environment) {
return new LoadBalancerZoneConfig(environment.getProperty("spring.cloud.loadbalancer.zone"));
}
@ConditionalOnMissingBean
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties, ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
clientFactory.setConfigurations(configurations.getIfAvailable(Collections::emptyList));
return clientFactory;
}
@Bean
public LoadBalancerEagerContextInitializer loadBalancerEagerContextInitializer(
LoadBalancerClientFactory clientFactory, LoadBalancerEagerLoadProperties properties) {
return new LoadBalancerEagerContextInitializer(clientFactory, properties.getClients());
}
@Bean
static LoadBalancerChildContextInitializer loadBalancerChildContextInitializer(
LoadBalancerClientFactory loadBalancerClientFactory, ApplicationContext parentContext) {
return new LoadBalancerChildContextInitializer(loadBalancerClientFactory, parentContext);
}
}
实战
java
package xyz.idoly.demo;
import java.util.Arrays;
import java.util.List;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestClient;
import reactor.core.publisher.Flux;
@Configuration
@LoadBalancerClient(value = "user-services", configuration = UserServicesLoadBalancerConfiguration.class)
public class RestClientConfig {
// 使用 @LoadBalanced 创建 RestClient.Builder
@Bean
@LoadBalanced
public RestClient.Builder loadBalancerRestClientBuilder() {
return RestClient.builder();
}
}
class UserServicesLoadBalancerConfiguration {
// 1. 创建自定义的 ReactorLoadBalancer 实现
// @Bean
// @Primary
// ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
// String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
// return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name
// );
// }
// 2. 创建 ServiceInstanceListSupplier,用于提供服务实例列表
@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier(Environment environment) {
// 返回自定义的服务实例列表提供者
return new UserServicesServiceInstanceListSupplier("user-services");
}
// 3. 自定义的 ServiceInstanceListSupplier 实现
static class UserServicesServiceInstanceListSupplier implements ServiceInstanceListSupplier {
private final String serviceId;
UserServicesServiceInstanceListSupplier(String serviceId) {
this.serviceId = serviceId;
}
@Override
public String getServiceId() {
return serviceId;
}
@Override
public Flux<List<ServiceInstance>> get() {
// 模拟返回多个服务实例
return Flux.just(Arrays.asList(
new DefaultServiceInstance(serviceId + "1", serviceId, "localhost", 8090, false),
new DefaultServiceInstance(serviceId + "2", serviceId, "localhost", 9090, false),
new DefaultServiceInstance(serviceId + "3", serviceId, "localhost", 9091, false)
));
}
}
}