From dca203ce653c3366b9073ad009b7c56fdd50395f Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 25 Jun 2025 16:40:20 +0800 Subject: [PATCH] feat:support setting load balancing strategy per service. --- .../LoadBalancerClientConfiguration.java | 33 +++++++++++++++++++ .../LoadBalancerClientConfigurationTests.java | 22 +++++++++++++ 2 files changed, 55 insertions(+) diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java index dd8a4fce7..8b2d50bcf 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfiguration.java @@ -30,6 +30,7 @@ import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; +import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; import org.springframework.cloud.loadbalancer.core.RetryAwareServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer; @@ -59,6 +60,7 @@ * @author BaoLin Zhu * @author changjin wei(魏昌进) * @author Zhuozhi Ji + * @author Haotian Zhang */ @Configuration(proxyBeanMethods = false) @ConditionalOnDiscoveryEnabled @@ -68,6 +70,7 @@ public class LoadBalancerClientConfiguration { @Bean @ConditionalOnMissingBean + @Conditional(DefaultStrategyCondition.class) public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); @@ -75,6 +78,16 @@ public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(E loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } + @Bean + @ConditionalOnMissingBean + @Conditional(RandomStrategyCondition.class) + public ReactorLoadBalancer randomLoadBalancer(Environment environment, + LoadBalancerClientFactory loadBalancerClientFactory) { + String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); + return new RandomLoadBalancer( + loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); + } + @Configuration(proxyBeanMethods = false) @ConditionalOnReactiveDiscoveryEnabled @Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER) @@ -309,6 +322,26 @@ public ServiceInstanceListSupplier retryAwareDiscoveryClientServiceInstanceListS } + static class DefaultStrategyCondition implements Condition { + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return LoadBalancerEnvironmentPropertyUtils.equalToForClientOrDefault(context.getEnvironment(), + "strategies", "default"); + } + + } + + static class RandomStrategyCondition implements Condition { + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return LoadBalancerEnvironmentPropertyUtils.equalToForClientOrDefault(context.getEnvironment(), + "strategies", "random"); + } + + } + static final class BlockingOnAvoidPreviousInstanceAndRetryEnabledCondition extends AllNestedConditions { private BlockingOnAvoidPreviousInstanceAndRetryEnabledCondition() { diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java index f9e4826c3..8aac0bf19 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/annotation/LoadBalancerClientConfigurationTests.java @@ -35,8 +35,11 @@ import org.springframework.cloud.loadbalancer.core.DelegatingServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.DiscoveryClientServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.HealthCheckServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; import org.springframework.cloud.loadbalancer.core.RequestBasedStickySessionServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.RetryAwareServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.WeightedServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.ZonePreferenceServiceInstanceListSupplier; @@ -54,6 +57,7 @@ * * @author Olga Maciaszek-Sharma * @author Zhuozhi Ji + * @author Haotian Zhang */ class LoadBalancerClientConfigurationTests { @@ -221,6 +225,24 @@ void shouldInstantiateBlockingWeightedServiceInstanceListSupplier() { }); } + @Test + void shouldInstantiateRoundRobinLoadBalancer() { + blockingDiscoveryClientRunner.withPropertyValues("spring.cloud.loadbalancer.strategies=default") + .run(context -> { + ReactorLoadBalancer reactorLoadBalancer = context.getBean(ReactorLoadBalancer.class); + then(reactorLoadBalancer).isInstanceOf(RoundRobinLoadBalancer.class); + }); + } + + @Test + void shouldInstantiateRandomLoadBalancer() { + blockingDiscoveryClientRunner.withPropertyValues("spring.cloud.loadbalancer.strategies=random") + .run(context -> { + ReactorLoadBalancer reactorLoadBalancer = context.getBean(ReactorLoadBalancer.class); + then(reactorLoadBalancer).isInstanceOf(RandomLoadBalancer.class); + }); + } + private static Stream blockingConfigurations() { return Stream.of(Arguments.of(RestTemplateTestConfig.class), Arguments.of(RestClientTestConfig.class), Arguments.of(RestTemplateAndRestClientConfig.class));