From 8b223ad9f5f918c8e7532852753780f489b92b76 Mon Sep 17 00:00:00 2001 From: joecqupt Date: Fri, 29 Aug 2025 01:12:06 +0800 Subject: [PATCH 1/3] fix update scoped routes order problem Signed-off-by: joecqupt --- .../cloud/gateway/route/CachingRouteLocator.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java index 5cf8cdae39..6c55e0fe49 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java @@ -16,6 +16,7 @@ package org.springframework.cloud.gateway.route; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -27,6 +28,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.Signal; +import reactor.util.function.Tuple2; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.event.RefreshRoutesResultEvent; @@ -88,9 +90,14 @@ public void onApplicationEvent(RefreshRoutesEvent event) { final Mono> scopedRoutes = fetch(event.getMetadata()).collect(Collectors.toList()) .onErrorResume(s -> Mono.just(List.of())); + Map routeIdToIdxMap = getRoutes().index() + .collectMap(t -> t.getT2().getId(), Tuple2::getT1) + .block(); + scopedRoutes.subscribe(scopedRoutesList -> { updateCache(Flux.concat(Flux.fromIterable(scopedRoutesList), getNonScopedRoutes(event)) - .sort(AnnotationAwareOrderComparator.INSTANCE)); + .sort(Comparator.comparing(r -> routeIdToIdxMap.getOrDefault(r.getId(), Long.MIN_VALUE))) + .sort(AnnotationAwareOrderComparator.INSTANCE)); }, this::handleRefreshError); } else { From db315beeab8a988528d7ffcd9404913f4dcac5fd Mon Sep 17 00:00:00 2001 From: joecqupt Date: Fri, 29 Aug 2025 14:03:14 +0800 Subject: [PATCH 2/3] add unit test Signed-off-by: joecqupt --- .../GatewayMetricsAutoConfiguration.java | 10 +++---- .../gateway/route/CachingRouteLocator.java | 8 ++--- .../config/GatewayAutoConfigurationTests.java | 4 +-- .../route/CachingRouteLocatorTests.java | 29 +++++++++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfiguration.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfiguration.java index 708fb8a459..606cc6a06f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfiguration.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayMetricsAutoConfiguration.java @@ -31,11 +31,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; -import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; -import org.springframework.boot.observation.autoconfigure.ObservationAutoConfiguration; -import org.springframework.boot.tracing.autoconfigure.MicrometerTracingAutoConfiguration; -import org.springframework.boot.tracing.autoconfigure.TracingProperties; +import org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration; +import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties; import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration; import org.springframework.cloud.gateway.filter.GatewayMetricsFilter; import org.springframework.cloud.gateway.filter.headers.observation.GatewayObservationConvention; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java index 6c55e0fe49..f8ab457da1 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java @@ -91,13 +91,13 @@ public void onApplicationEvent(RefreshRoutesEvent event) { .onErrorResume(s -> Mono.just(List.of())); Map routeIdToIdxMap = getRoutes().index() - .collectMap(t -> t.getT2().getId(), Tuple2::getT1) - .block(); + .collectMap(t -> t.getT2().getId(), Tuple2::getT1) + .block(); scopedRoutes.subscribe(scopedRoutesList -> { updateCache(Flux.concat(Flux.fromIterable(scopedRoutesList), getNonScopedRoutes(event)) - .sort(Comparator.comparing(r -> routeIdToIdxMap.getOrDefault(r.getId(), Long.MIN_VALUE))) - .sort(AnnotationAwareOrderComparator.INSTANCE)); + .sort(Comparator.comparing(r -> routeIdToIdxMap.getOrDefault(r.getId(), Long.MIN_VALUE))) + .sort(AnnotationAwareOrderComparator.INSTANCE)); }, this::handleRefreshError); } else { diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java index 09d1167da2..10a27efef9 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java @@ -44,8 +44,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ssl.SslBundleRegistrar; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; -import org.springframework.boot.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration; +import org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.security.autoconfigure.reactive.ReactiveSecurityAutoConfiguration; import org.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientAutoConfiguration; import org.springframework.boot.ssl.DefaultSslBundleRegistry; diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java index d5609ea847..b8d0ee5d65 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java @@ -17,7 +17,9 @@ package org.springframework.cloud.gateway.route; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -117,6 +119,23 @@ else if (i == 2) { } + @Test + public void updateScopedRoutes() { + Map metadata = Map.of("metadata-key1", "metadata-value1"); + int order = 0; + Route route1 = route(1, order, Collections.EMPTY_MAP); + Route route2 = route(2, order, metadata); + CachingRouteLocator locator = new CachingRouteLocator(() -> Flux.just(route1, route2)); + + List routes = locator.getRoutes().collectList().block(); + assertThat(routes).containsExactly(route1, route2); + + RefreshRoutesEvent event = new RefreshRoutesEvent(this, metadata); + locator.onApplicationEvent(event); + routes = locator.getRoutes().collectList().block(); + assertThat(routes).containsExactly(route1, route2); + } + private void waitUntilRefreshFinished(CachingRouteLocator locator, List resultEvents) throws InterruptedException { CountDownLatch cdl = new CountDownLatch(1); @@ -129,6 +148,16 @@ private void waitUntilRefreshFinished(CachingRouteLocator locator, List metadata) { + return Route.async() + .id(String.valueOf(id)) + .uri("http://localhost/" + id) + .order(order) + .predicate(exchange -> true) + .metadata(metadata) + .build(); + } + Route route(int id) { return Route.async() .id(String.valueOf(id)) From ea1af81f5fe272ad13d4312e6f387a27b7fa3245 Mon Sep 17 00:00:00 2001 From: joecqupt Date: Fri, 29 Aug 2025 15:10:33 +0800 Subject: [PATCH 3/3] update Signed-off-by: joecqupt --- .../cloud/gateway/route/CachingRouteLocator.java | 7 +++---- .../gateway/route/CachingRouteLocatorTests.java | 12 ++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java index f8ab457da1..178103f41d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.route; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -28,7 +29,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.Signal; -import reactor.util.function.Tuple2; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.event.RefreshRoutesResultEvent; @@ -90,9 +90,8 @@ public void onApplicationEvent(RefreshRoutesEvent event) { final Mono> scopedRoutes = fetch(event.getMetadata()).collect(Collectors.toList()) .onErrorResume(s -> Mono.just(List.of())); - Map routeIdToIdxMap = getRoutes().index() - .collectMap(t -> t.getT2().getId(), Tuple2::getT1) - .block(); + Map routeIdToIdxMap = new HashMap<>(); + getRoutes().index().subscribe(t -> routeIdToIdxMap.put(t.getT2().getId(), t.getT1())); scopedRoutes.subscribe(scopedRoutesList -> { updateCache(Flux.concat(Flux.fromIterable(scopedRoutesList), getNonScopedRoutes(event)) diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java index b8d0ee5d65..58862704bd 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/CachingRouteLocatorTests.java @@ -150,12 +150,12 @@ private void waitUntilRefreshFinished(CachingRouteLocator locator, List metadata) { return Route.async() - .id(String.valueOf(id)) - .uri("http://localhost/" + id) - .order(order) - .predicate(exchange -> true) - .metadata(metadata) - .build(); + .id(String.valueOf(id)) + .uri("http://localhost/" + id) + .order(order) + .predicate(exchange -> true) + .metadata(metadata) + .build(); } Route route(int id) {