diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java index 50ba6a18..80b6600f 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/DelegatingServiceInstanceListSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.loadbalancer.core; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.cloud.client.ServiceInstance; import org.springframework.util.Assert; /** @@ -26,9 +27,10 @@ import org.springframework.util.Assert; * * @author Spencer Gibb * @author Olga Maciaszek-Sharma + * @author Jürgen Kreitler */ public abstract class DelegatingServiceInstanceListSupplier - implements ServiceInstanceListSupplier, InitializingBean, DisposableBean { + implements ServiceInstanceListSupplier, SelectedInstanceCallback, InitializingBean, DisposableBean { protected final ServiceInstanceListSupplier delegate; @@ -46,6 +48,13 @@ public abstract class DelegatingServiceInstanceListSupplier return this.delegate.getServiceId(); } + @Override + public void selectedServiceInstance(ServiceInstance serviceInstance) { + if (delegate instanceof SelectedInstanceCallback selectedInstanceCallbackDelegate) { + selectedInstanceCallbackDelegate.selectedServiceInstance(serviceInstance); + } + } + @Override public void afterPropertiesSet() throws Exception { if (delegate instanceof InitializingBean) { diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java index d198051a..8d8e63f2 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.cloud.client.ServiceInstance; * chosen instance if it's available. * * @author Olga Maciaszek-Sharma + * @author Jürgen Kreitler * @since 2.2.7 */ public class SameInstancePreferenceServiceInstanceListSupplier extends DelegatingServiceInstanceListSupplier @@ -72,6 +73,7 @@ public class SameInstancePreferenceServiceInstanceListSupplier extends Delegatin @Override public void selectedServiceInstance(ServiceInstance serviceInstance) { + super.selectedServiceInstance(serviceInstance); if (previouslyReturnedInstance == null || !previouslyReturnedInstance.equals(serviceInstance)) { previouslyReturnedInstance = serviceInstance; } diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RetryAwareServiceInstanceListSupplierTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RetryAwareServiceInstanceListSupplierTests.java index b8882630..75ebc8b8 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RetryAwareServiceInstanceListSupplierTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RetryAwareServiceInstanceListSupplierTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,11 +27,16 @@ import org.springframework.cloud.client.loadbalancer.RetryableRequestContext; import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; /** * Tests for {@link RetryAwareServiceInstanceListSupplier}. * * @author Olga Maciaszek-Sharma + * @author Jürgen Kreitler */ class RetryAwareServiceInstanceListSupplierTests { @@ -78,4 +83,12 @@ class RetryAwareServiceInstanceListSupplierTests { assertThat(returnedInstances).containsExactly(firstInstance); } + @Test + void shouldCallSelectedServiceInstanceOnItsDelegate() { + ServiceInstance firstInstance = instance(serviceId, "1host", false); + TestSelectedServiceInstanceSupplier delegate = mock(TestSelectedServiceInstanceSupplier.class); + DelegatingServiceInstanceListSupplier supplier = new RetryAwareServiceInstanceListSupplier(delegate); + supplier.selectedServiceInstance(firstInstance); + verify(delegate, times(1)).selectedServiceInstance(any(ServiceInstance.class)); + } } diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java index 50aa8e41..48d70d08 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,13 @@ import static java.lang.Integer.MIN_VALUE; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * @author Zhuozhi JI + * @author Jürgen Kreitler */ class RoundRobinLoadBalancerTests { @@ -68,6 +71,18 @@ class RoundRobinLoadBalancerTests { assertThat(loadBalancer.position).hasValue(0); } + @Test + void shouldCallSelectedServiceInstanceIfSupplierOrItsDelegateIsInstanceOf() { + TestSelectedServiceInstanceSupplier delegate = mock(TestSelectedServiceInstanceSupplier.class); + DelegatingServiceInstanceListSupplier supplier = new RetryAwareServiceInstanceListSupplier(delegate); + when(delegate.get(any())).thenReturn(Flux.just(Collections.singletonList(new DefaultServiceInstance()))); + RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(supplier), + "shouldNotMovePositionIfOnlyOneInstance", 0); + + loadBalancer.choose().block(); + verify(delegate, times(1)).selectedServiceInstance(any(ServiceInstance.class)); + } + @SuppressWarnings("all") void assertOrderEnforced(int seed) { List instances = new ArrayList<>(); diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java index fd66a251..3aeec9b1 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,13 +26,17 @@ import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * Tests for {@link SameInstancePreferenceServiceInstanceListSupplier}. * * @author Olga Maciaszek-Sharma + * @author Jürgen Kreitler */ class SameInstancePreferenceServiceInstanceListSupplierTests { @@ -78,6 +82,15 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { assertThat(instances).hasSize(2); } + @Test + void shouldCallSelectedServiceInstanceOnItsDelegate() { + ServiceInstance firstInstance = serviceInstance("test-4"); + TestSelectedServiceInstanceSupplier delegate = mock(TestSelectedServiceInstanceSupplier.class); + DelegatingServiceInstanceListSupplier supplier = new SameInstancePreferenceServiceInstanceListSupplier(delegate); + supplier.selectedServiceInstance(firstInstance); + verify(delegate, times(1)).selectedServiceInstance(any(ServiceInstance.class)); + } + private DefaultServiceInstance serviceInstance(String instanceId) { return new DefaultServiceInstance(instanceId, "test", "http://test.test", 9080, false); } diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/TestSelectedServiceInstanceSupplier.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/TestSelectedServiceInstanceSupplier.java new file mode 100644 index 00000000..97fcf4e8 --- /dev/null +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/TestSelectedServiceInstanceSupplier.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.loadbalancer.core; + +/** + * Test supplier interface extending {@link ServiceInstanceListSupplier} and {@link SelectedInstanceCallback}. + * Useful if you need to verify certain behavior happened on a mock for example. + * + * @author Jürgen Kreitler + */ +public interface TestSelectedServiceInstanceSupplier extends ServiceInstanceListSupplier, SelectedInstanceCallback { +}