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

[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.xdnf.cn/news/17113.html

相关文章:

  • 【Linux | 网络】网络层(IP协议、NAT技术和ICMP协议)
  • SpringBoot整合t-io是websocket实时通信
  • LeetCode 分类刷题:16. 最接近的三数之和
  • 《汇编语言:基于X86处理器》第11章 复习题和练习
  • uiautomator2 编写测试流程-登陆后的酷狗01
  • 进程生命周期管理:从创建到终止的完整逻辑
  • 探索医学领域多模态人工智能的发展图景:技术挑战与临床应用的范围综述|文献速递-医学影像算法文献分享
  • iOS 内测上架流程详解:跨平台团队如何快速部署 TestFlight
  • 注解知识学习
  • 凹槽类零部件尺寸的检测方法有哪些 - 激光频率梳 3D 轮廓检测
  • [硬件电路-156]:什么是电信号? 电信号的本质:电信号是随时间变化的电压或电流。本质是电子运动表征信息,兼具能量传输与信息编码传递功能。
  • Mac电脑基本功能快捷键
  • EdgeView for macOS:解决图像管理痛点的利器
  • 设计模式 -> 策略模式(Strategy Pattern)
  • 经典设计模式
  • 验证码等待时间技术在酒店自助入住、美容自助与社区场景中的应用必要性研究—仙盟创梦IDE
  • Calcite自定义扩展SQL案例详细流程篇
  • 六、Linux核心服务与包管理
  • 前端 拼多多4399笔试题目
  • [自动化Adapt] 录制引擎 | iframe 穿透 | NTP | AIOSQLite | 数据分片
  • Connection refused: no further information: localhost/127.0.0.1:2375
  • 第四章:OSPF 协议
  • ssh服务器端口和本地端口映射
  • [spring-cloud: 服务发现]-源码解析
  • 旧笔记本电脑如何安装飞牛OS
  • 电商系统定制开发流程:ZKmall开源商城需求分析到上线全程可控
  • MySQL深度理解-MySQL锁机制
  • 【Mysql】日志--错误日志、二进制日志、查询日志、慢查询日志
  • Shell脚本-变量的定义规则
  • LLM调研