Use reactive discovery client for DiscoveryClientRouteDefinitionLocator

This commit is contained in:
Tim Ysewyn
2019-10-03 12:56:24 +02:00
committed by GitHub
parent 4c467788f0
commit 9492a63c55
5 changed files with 60 additions and 34 deletions

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.gateway.discovery;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
@@ -27,6 +28,7 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
@@ -49,23 +51,45 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc
private static final Log log = LogFactory
.getLog(DiscoveryClientRouteDefinitionLocator.class);
private final DiscoveryClient discoveryClient;
private final DiscoveryLocatorProperties properties;
private final String routeIdPrefix;
private final SimpleEvaluationContext evalCtxt;
private Flux<List<ServiceInstance>> serviceInstances;
/**
* Kept for backwards compatibility. You should use the reactive discovery client.
* @param discoveryClient the blocking discovery client
* @param properties the configuration properties
* @deprecated kept for backwards compatibility
*/
@Deprecated
public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient,
DiscoveryLocatorProperties properties) {
this.discoveryClient = discoveryClient;
this(discoveryClient.getClass().getSimpleName(), properties);
serviceInstances = Flux
.defer(() -> Flux.fromIterable(discoveryClient.getServices()))
.map(discoveryClient::getInstances)
.subscribeOn(Schedulers.boundedElastic());
}
public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient,
DiscoveryLocatorProperties properties) {
this(discoveryClient.getClass().getSimpleName(), properties);
serviceInstances = discoveryClient.getServices()
.flatMap(service -> discoveryClient.getInstances(service).collectList());
}
private DiscoveryClientRouteDefinitionLocator(String discoveryClientName,
DiscoveryLocatorProperties properties) {
this.properties = properties;
if (StringUtils.hasText(properties.getRouteIdPrefix())) {
this.routeIdPrefix = properties.getRouteIdPrefix();
routeIdPrefix = properties.getRouteIdPrefix();
}
else {
this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
routeIdPrefix = discoveryClientName + "_";
}
evalCtxt = SimpleEvaluationContext.forReadOnlyDataBinding().withInstanceMethods()
.build();
@@ -94,9 +118,7 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc
};
}
return Flux.defer(() -> Flux.fromIterable(discoveryClient.getServices()))
.subscribeOn(Schedulers.elastic()).map(discoveryClient::getInstances)
.filter(instances -> !instances.isEmpty())
return serviceInstances.filter(instances -> !instances.isEmpty())
.map(instances -> instances.get(0)).filter(includePredicate)
.map(instance -> {
String serviceId = instance.getServiceId();

View File

@@ -25,7 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.filter.FilterDefinition;
@@ -49,7 +49,7 @@ import static org.springframework.cloud.gateway.support.NameUtils.normalizeRoute
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@AutoConfigureAfter(CompositeDiscoveryClientAutoConfiguration.class)
@ConditionalOnClass({ DispatcherHandler.class, DiscoveryClient.class })
@ConditionalOnClass({ DispatcherHandler.class, ReactiveDiscoveryClient.class })
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
@@ -81,10 +81,11 @@ public class GatewayDiscoveryClientAutoConfiguration {
}
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
ReactiveDiscoveryClient discoveryClient,
DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}

View File

@@ -16,13 +16,12 @@
package org.springframework.cloud.gateway.discovery;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
@@ -30,7 +29,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
@@ -84,7 +83,7 @@ public class DiscoveryClientRouteDefinitionLocatorIntegrationTests {
}
private static class TestDiscoveryClient implements DiscoveryClient {
private static class TestDiscoveryClient implements ReactiveDiscoveryClient {
AtomicBoolean single = new AtomicBoolean(true);
@@ -104,22 +103,22 @@ public class DiscoveryClientRouteDefinitionLocatorIntegrationTests {
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
public Flux<ServiceInstance> getInstances(String serviceId) {
if (serviceId.equals("service1")) {
return Collections.singletonList(instance1);
return Flux.just(instance1);
}
if (serviceId.equals("service2")) {
return Collections.singletonList(instance2);
return Flux.just(instance2);
}
return Collections.emptyList();
return Flux.empty();
}
@Override
public List<String> getServices() {
public Flux<String> getServices() {
if (single.get()) {
return Collections.singletonList("service1");
return Flux.just("service1");
}
return Arrays.asList("service1", "service2");
return Flux.just("service1", "service2");
}
}

View File

@@ -16,20 +16,20 @@
package org.springframework.cloud.gateway.discovery;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
@@ -95,22 +95,22 @@ public class DiscoveryClientRouteDefinitionLocatorTests {
protected static class Config {
@Bean
DiscoveryClient discoveryClient() {
DiscoveryClient discoveryClient = mock(DiscoveryClient.class);
ReactiveDiscoveryClient discoveryClient() {
ReactiveDiscoveryClient discoveryClient = mock(ReactiveDiscoveryClient.class);
when(discoveryClient.getServices())
.thenReturn(Arrays.asList("SERVICE1", "Service2"));
.thenReturn(Flux.just("SERVICE1", "Service2"));
whenInstance(discoveryClient, "SERVICE1",
Collections.singletonMap("edge", "true"));
whenInstance(discoveryClient, "Service2", Collections.emptyMap());
return discoveryClient;
}
private void whenInstance(DiscoveryClient discoveryClient, String serviceId,
Map<String, String> metadata) {
private void whenInstance(ReactiveDiscoveryClient discoveryClient,
String serviceId, Map<String, String> metadata) {
DefaultServiceInstance instance1 = new DefaultServiceInstance(serviceId,
"localhost", 8001, false, metadata);
when(discoveryClient.getInstances(serviceId))
.thenReturn(Collections.singletonList(instance1));
.thenReturn(Flux.just(instance1));
}
}

View File

@@ -19,18 +19,20 @@ package org.springframework.cloud.gateway.discovery;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.gateway.config.LoadBalancerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(Enclosed.class)
public class GatewayDiscoveryClientAutoConfigurationTests {
@@ -80,8 +82,10 @@ public class GatewayDiscoveryClientAutoConfigurationTests {
protected static class Config {
@Bean
DiscoveryClient discoveryClient() {
return mock(DiscoveryClient.class);
ReactiveDiscoveryClient discoveryClient() {
ReactiveDiscoveryClient discoveryClient = mock(ReactiveDiscoveryClient.class);
when(discoveryClient.getServices()).thenReturn(Flux.empty());
return discoveryClient;
}
}