当前位置: 首页 > news >正文

[spring-cloud: @LoadBalanced @LoadBalancerClient]-源码分析

源码

LoadBalanced

@LoadBalanced 注解用于标记 RestTemplateRestClient.BuilderWebClient.Builder Bean,使其自动集成负载均衡客户端,实现在请求时自动通过负载均衡器选择服务实例。

// LoadBalancerRestClientBuilderBeanPostProcessor
// LoadBalancerWebClientBuilderBeanPostProcessor
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {}

LoadBalancerAutoConfiguration

@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();@Beanpublic SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {return () -> restTemplateCustomizers.ifAvailable(customizers -> {for (RestTemplate restTemplate : restTemplates) {// LoadBalancerInterceptorConfig.restTemplateCustomizer: // 	   LoadBalancerInterceptor// RetryInterceptorAutoConfiguration.restTemplateCustomizer: // 	   RetryLoadBalancerInterceptorfor (RestTemplateCustomizer customizer : customizers) {customizer.customize(restTemplate);}}});}@Bean@ConditionalOnMissingBeanpublic LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {return new LoadBalancerRequestFactory(loadBalancerClient, transformers);}// DeferringLoadBalancerInterceptorConfig// LoadBalancerInterceptorConfig // RetryInterceptorAutoConfiguration
}
@AutoConfiguration
static class DeferringLoadBalancerInterceptorConfig {@Bean@ConditionalOnMissingBeanpublic DeferringLoadBalancerInterceptor deferringLoadBalancerInterceptor(ObjectProvider<BlockingLoadBalancerInterceptor> loadBalancerInterceptorObjectProvider) {return new DeferringLoadBalancerInterceptor(loadBalancerInterceptorObjectProvider);}@Bean@ConditionalOnBean(DeferringLoadBalancerInterceptor.class)@ConditionalOnMissingBeanLoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor(DeferringLoadBalancerInterceptor loadBalancerInterceptor, ApplicationContext context) {return new LoadBalancerRestClientBuilderBeanPostProcessor(loadBalancerInterceptor, context);}}
@AutoConfiguration
@Conditional(RetryMissingOrDisabledCondition.class)
static class LoadBalancerInterceptorConfig {@Beanpublic LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,LoadBalancerRequestFactory requestFactory) {return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);}@Bean@ConditionalOnMissingBeanpublic 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 {}}
/*** Auto configuration for retry mechanism.*/
@AutoConfiguration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic RetryLoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory,ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {return new RetryLoadBalancerInterceptor(loadBalancerClient, requestFactory, loadBalancedRetryFactory,loadBalancerFactory);}@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(RetryLoadBalancerInterceptor loadBalancerInterceptor) {return restTemplate -> {List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);restTemplate.setInterceptors(list);};}
}

LoadBalancerClient

@LoadBalancerClient 注解用于配置一个负载均衡客户端,通常应用于 @Configuration 类中,结合 LoadBalancerClientFactory 可获取配置的负载均衡客户端。它允许指定客户端名称、配置类等自定义负载均衡行为。

@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 上下文中。

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());}@Overridepublic 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 创建子容器,管理客户端和负载均衡器的实例。

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);}@Overridepublic ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);}@Overridepublic 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 defaultreturn 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 配置,包括 LoadBalancerClientFactoryLoadBalancerZoneConfigLoadBalancerEagerContextInitializer,并根据配置条件自动启用负载均衡功能。

@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@ConditionalOnMissingBeanpublic LoadBalancerZoneConfig zoneConfig(Environment environment) {return new LoadBalancerZoneConfig(environment.getProperty("spring.cloud.loadbalancer.zone"));}@ConditionalOnMissingBean@Beanpublic LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties, ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);clientFactory.setConfigurations(configurations.getIfAvailable(Collections::emptyList));return clientFactory;}@Beanpublic LoadBalancerEagerContextInitializer loadBalancerEagerContextInitializer(LoadBalancerClientFactory clientFactory, LoadBalancerEagerLoadProperties properties) {return new LoadBalancerEagerContextInitializer(clientFactory, properties.getClients());}@Beanstatic LoadBalancerChildContextInitializer loadBalancerChildContextInitializer(LoadBalancerClientFactory loadBalancerClientFactory, ApplicationContext parentContext) {return new LoadBalancerChildContextInitializer(loadBalancerClientFactory, parentContext);}}

实战

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@LoadBalancedpublic 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,用于提供服务实例列表@Beanpublic 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;}@Overridepublic String getServiceId() {return serviceId;}@Overridepublic 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)));}}
}
http://www.lryc.cn/news/609438.html

相关文章:

  • DevOps平台大比拼:Gitee、Jenkins与CircleCI如何选型?
  • 集成电路学习:什么是BLE Mesh低功耗蓝牙网络
  • AI产品经理手册(Ch6-8)AI Product Manager‘s Handbook学习笔记
  • Cursor国产平替重磅开源!离线研发AI助手,拒绝云端受制于人
  • 8位以及32位的MCU如何进行选择?
  • 苹果iOS应用ipa文件安装之前?为什么需要签名?不签名能用么?
  • Memcached 缓存详解及常见问题解决方案
  • 零售消费行业研究系列报告
  • 【C++】2. 类和对象(上)
  • java~final关键字
  • sqli-labs-master/Less-31~Less-40
  • numpy数组拼接 - np.concatenate
  • 张 事实关注增强模型:提升AI准确率新方法
  • 数据结构:反转链表(reverse the linked list)
  • 通用 PDF 文件流 OCR 到文本 API 接口
  • 【unitrix】 7.2 二进制位减法(bit_sub.rs)
  • steam Rust游戏 启动错误,删除sys驱动,亲测有效。
  • 力扣301:删除无效的括号
  • 【量化交易】日内交易有效特征因子
  • 【解决办法】报错Found dtype Long but expected Float
  • 数据集相关类代码回顾理解 | StratifiedShuffleSplit\transforms.ToTensor\Counter
  • Kubernetes 节点摘除指南
  • 模型预估打分对运筹跟踪的影响
  • SaProt 模型部署与运行教程
  • 从0搭建YOLO目标检测系统:实战项目+完整流程+界面开发(附源码)
  • 数据结构学习(day01)
  • 1、docker容器命令 | 生命周期管理
  • 多模态后训练反常识:长思维链SFT和RL的协同困境
  • Spring Batch的2种STEP定义方式
  • 最新Android Studio汉化教程--兼容插件包