Adds CachingRouteReader
This allows an atomic refresh of routes.
This commit is contained in:
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.cloud.gateway.api.CachingRouteReader;
|
||||
import org.springframework.cloud.gateway.api.RouteReader;
|
||||
import org.springframework.cloud.gateway.config.Route;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
@@ -13,9 +14,11 @@ import org.springframework.cloud.gateway.handler.FilteringWebHandler;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
@@ -43,9 +46,17 @@ public class GatewayEndpoint {/*extends AbstractEndpoint<Map<String, Object>> {*
|
||||
|
||||
/*@Override
|
||||
public Map<String, Object> invoke() {
|
||||
|
||||
}*/
|
||||
|
||||
//TODO: this should really be a listener that responds to a RefreshEvent
|
||||
@PostMapping("/refresh")
|
||||
public Flux<Route> refresh() {
|
||||
if (this.routeReader instanceof CachingRouteReader) {
|
||||
return ((CachingRouteReader)this.routeReader).refresh();
|
||||
}
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
@GetMapping("/globalfilters")
|
||||
public Map<String, Object> globalfilters() {
|
||||
return getNamesToOrders(this.globalFilters);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.springframework.cloud.gateway.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.springframework.cloud.gateway.config.Route;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class CachingRouteReader implements RouteReader {
|
||||
|
||||
private final RouteReader delegate;
|
||||
private final AtomicReference<List<Route>> cachedRoutes = new AtomicReference<>();
|
||||
|
||||
public CachingRouteReader(RouteReader delegate) {
|
||||
this.delegate = delegate;
|
||||
this.cachedRoutes.compareAndSet(null, collectRoutes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Route> getRoutes() {
|
||||
return Flux.fromIterable(this.cachedRoutes.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new routes
|
||||
* @return old routes
|
||||
*/
|
||||
public Flux<Route> refresh() {
|
||||
return Flux.fromIterable(this.cachedRoutes.getAndUpdate(
|
||||
routes -> CachingRouteReader.this.collectRoutes()));
|
||||
}
|
||||
|
||||
private List<Route> collectRoutes() {
|
||||
return this.delegate.getRoutes().collectList().block();
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.gateway.actuate.GatewayEndpoint;
|
||||
import org.springframework.cloud.gateway.api.CachingRouteReader;
|
||||
import org.springframework.cloud.gateway.api.RouteReader;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
|
||||
@@ -67,8 +68,9 @@ public class GatewayAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(RouteReader.class)
|
||||
public PropertiesRouteReader propertiesRouteReader(GatewayProperties properties) {
|
||||
return new PropertiesRouteReader(properties);
|
||||
public RouteReader propertiesRouteReader(GatewayProperties properties) {
|
||||
//TODO: how to automatically apply CachingRouteReader
|
||||
return new CachingRouteReader(new PropertiesRouteReader(properties));
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -31,8 +31,6 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
|
||||
private RouteReader routeReader;
|
||||
private WebHandler webHandler;
|
||||
|
||||
private List<Route> routes;
|
||||
|
||||
public RoutePredicateHandlerMapping(WebHandler webHandler, Map<String, RoutePredicate> predicates,
|
||||
RouteReader routeReader) {
|
||||
this.webHandler = webHandler;
|
||||
@@ -58,24 +56,13 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
|
||||
return name.replace(RoutePredicate.class.getSimpleName(), "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initApplicationContext() throws BeansException {
|
||||
super.initApplicationContext();
|
||||
Flux<Route> routes = this.routeReader.getRoutes();
|
||||
registerHandlers(routes.collectList().block()); //TODO: convert rest of class to Reactive
|
||||
}
|
||||
|
||||
protected void registerHandlers(List<Route> routes) {
|
||||
this.routes = routes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
|
||||
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().getSimpleName());
|
||||
|
||||
Route route;
|
||||
try {
|
||||
route = lookupRoute(this.routes, exchange);
|
||||
route = lookupRoute(exchange);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return Mono.error(ex);
|
||||
@@ -107,7 +94,9 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
|
||||
}
|
||||
|
||||
|
||||
protected Route lookupRoute(List<Route> routes, ServerWebExchange exchange) throws Exception {
|
||||
protected Route lookupRoute(ServerWebExchange exchange) throws Exception {
|
||||
List<Route> routes = this.routeReader.getRoutes().collectList().block(); //TODO: convert rest of class to Reactive
|
||||
|
||||
for (Route route : routes) {
|
||||
if (!route.getPredicates().isEmpty()) {
|
||||
//TODO: cache predicate
|
||||
|
||||
@@ -5,7 +5,9 @@ import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.gateway.api.CachingRouteReader;
|
||||
import org.springframework.cloud.gateway.api.CompositeRouteReader;
|
||||
import org.springframework.cloud.gateway.api.RouteReader;
|
||||
import org.springframework.cloud.gateway.config.GatewayProperties;
|
||||
import org.springframework.cloud.gateway.config.PropertiesRouteReader;
|
||||
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteReader;
|
||||
@@ -42,9 +44,11 @@ public class GatewayTestApplication {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public CompositeRouteReader compositeRouteReader(DiscoveryClientRouteReader discoveryClientRouteReader,
|
||||
PropertiesRouteReader propertiesRouteReader) {
|
||||
return new CompositeRouteReader(Flux.just(discoveryClientRouteReader, propertiesRouteReader));
|
||||
public RouteReader compositeRouteReader(DiscoveryClientRouteReader discoveryClientRouteReader,
|
||||
PropertiesRouteReader propertiesRouteReader) {
|
||||
final Flux<RouteReader> flux = Flux.just(discoveryClientRouteReader, propertiesRouteReader);
|
||||
final CompositeRouteReader composite = new CompositeRouteReader(flux);
|
||||
return new CachingRouteReader(composite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user