From 63fc79c5b649a5a48b49cd61481d1483d2563a77 Mon Sep 17 00:00:00 2001 From: Marta Medio Date: Thu, 23 Nov 2023 13:11:28 +0100 Subject: [PATCH 1/5] Add links to child paths for /actuator/gateway endpoint --- .../AbstractGatewayControllerEndpoint.java | 59 +++++++++++++++ .../gateway/actuate/GatewayEndpointInfo.java | 71 +++++++++++++++++++ .../GatewayControllerEndpointTests.java | 9 +++ 3 files changed, 139 insertions(+) create mode 100644 spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayEndpointInfo.java diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java index fd31bf68..ab521961 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java @@ -16,12 +16,16 @@ package org.springframework.cloud.gateway.actuate; +import java.io.IOException; import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -34,6 +38,7 @@ import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory; +import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionLocator; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; @@ -42,6 +47,9 @@ import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.Ordered; +import org.springframework.core.type.MethodMetadata; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.CollectionUtils; @@ -51,6 +59,8 @@ 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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.server.ResponseStatusException; @@ -61,6 +71,8 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis private static final Log log = LogFactory.getLog(GatewayControllerEndpoint.class); + private static final String ENDPOINT_PREFIX = "/actuator/gateway"; + protected RouteDefinitionLocator routeDefinitionLocator; protected List globalFilters; @@ -88,6 +100,53 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis this.routeLocator = routeLocator; } + private List getAvailableEndpointsForClass(String className) { + try { + MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(className); + Set annotatedMethods = metadataReader.getAnnotationMetadata() + .getAnnotatedMethods(RequestMapping.class.getName()); + + return annotatedMethods.stream().map(method -> new GatewayEndpointInfo(ENDPOINT_PREFIX + + ((String[]) method.getAnnotationAttributes(RequestMapping.class.getName()).get("path"))[0], + ((RequestMethod[]) method.getAnnotationAttributes(RequestMapping.class.getName()).get("method"))[0] + .name())) + .collect(Collectors.toList()); + } + catch (IOException exception) { + log.warn(exception.getMessage()); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage()); + } + } + + public static List mergeEndpoints(List listA, + List listB) { + Map> mergedMap = new HashMap<>(); + + Stream.concat(listA.stream(), listB.stream()).forEach(e -> mergedMap + .computeIfAbsent(e.getHref(), k -> new ArrayList<>()).addAll(Arrays.asList(e.getMethods()))); + + return mergedMap.entrySet().stream().map(entry -> new GatewayEndpointInfo(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + GatewayEndpointInfo generateHref(Route r, GatewayEndpointInfo path) { + return new GatewayEndpointInfo(path.getHref().replace("{id}", r.getId()), Arrays.asList(path.getMethods())); + } + + @GetMapping("/") + public Mono> getEndpoints() { + List endpoints = mergeEndpoints( + getAvailableEndpointsForClass(AbstractGatewayControllerEndpoint.class.getName()), + getAvailableEndpointsForClass(GatewayControllerEndpoint.class.getName())); + + return Flux.fromIterable(endpoints).map(p -> p) + .flatMap(path -> this.routeLocator.getRoutes().map(r -> generateHref(r, path)).distinct().collectList() + .flatMapMany(Flux::fromIterable)) + .distinct() // Ensure overall uniqueness + .collectList(); + + } + @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayEndpointInfo.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayEndpointInfo.java new file mode 100644 index 00000000..ffb1cf21 --- /dev/null +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayEndpointInfo.java @@ -0,0 +1,71 @@ +/* + * Copyright 2013-2020 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.gateway.actuate; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * @author Marta Medio + */ +class GatewayEndpointInfo { + + private String href; + + private List methods; + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public String[] getMethods() { + return methods.stream().toArray(String[]::new); + } + + GatewayEndpointInfo(String href, String method) { + this.href = href; + this.methods = Collections.singletonList(method); + } + + GatewayEndpointInfo(String href, List methods) { + this.href = href; + this.methods = methods; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GatewayEndpointInfo that = (GatewayEndpointInfo) o; + return Objects.equals(href, that.href) && Objects.equals(methods, that.methods); + } + + @Override + public int hashCode() { + return Objects.hash(href, methods); + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java index 193761a5..3909761a 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java @@ -68,6 +68,15 @@ public class GatewayControllerEndpointTests { @LocalServerPort int port; + @Test + public void testEndpoints() { + testClient.get().uri("http://localhost:" + port + "/actuator/gateway").exchange().expectStatus().isOk() + .expectBody(List.class).consumeWith(result -> { + List responseBody = result.getResponseBody(); + assertThat(responseBody).isNotEmpty(); + }); + } + @Test public void testRefresh() { testClient.post().uri("http://localhost:" + port + "/actuator/gateway/refresh").exchange().expectStatus() From f782783f3c4e5555973509249fe08a5c590f3093 Mon Sep 17 00:00:00 2001 From: Marta Medio Date: Thu, 23 Nov 2023 13:12:02 +0100 Subject: [PATCH 2/5] Add docs with output of gateway actuator endpoint --- .../main/asciidoc/spring-cloud-gateway.adoc | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/src/main/asciidoc/spring-cloud-gateway.adoc b/docs/src/main/asciidoc/spring-cloud-gateway.adoc index f7ce13cc..d0ef4e5d 100644 --- a/docs/src/main/asciidoc/spring-cloud-gateway.adoc +++ b/docs/src/main/asciidoc/spring-cloud-gateway.adoc @@ -2787,6 +2787,50 @@ management.endpoints.web.exposure.include=gateway ---- ==== +This endpoint provides an overview of what is available on the child actuator endpoint and the available methods for each reference. The resulting response is similar to the following: + +[source,json] +---- +[ + { + "href":"/actuator/gateway/", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/routedefinitions", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/globalfilters", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/routefilters", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/routes", + "methods":[ "POST", "GET" ] + }, + { + "href":"/actuator/gateway/routepredicates", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/refresh", + "methods":[ "POST" ] + }, + { + "href":"/actuator/gateway/routes/route-id-1/combinedfilters", + "methods":[ "GET" ] + }, + { + "href":"/actuator/gateway/routes/route-id-1", + "methods":[ "POST", "DELETE", "GET" ] + } +] +---- + === Verbose Actuator Format A new, more verbose format has been added to Spring Cloud Gateway. From 8157363258181a03715ad9b0e9854bf12be1b475 Mon Sep 17 00:00:00 2001 From: Fredrich Ombico Date: Tue, 5 Dec 2023 13:47:16 -0500 Subject: [PATCH 3/5] Test additional endpoints --- .../GatewayControllerEndpointTests.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java index 3909761a..05878ff5 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java @@ -70,10 +70,29 @@ public class GatewayControllerEndpointTests { @Test public void testEndpoints() { - testClient.get().uri("http://localhost:" + port + "/actuator/gateway").exchange().expectStatus().isOk() - .expectBody(List.class).consumeWith(result -> { - List responseBody = result.getResponseBody(); + testClient.get().uri("http://localhost:" + port + "/actuator/gateway").exchange() + .expectStatus().isOk().expectBodyList(Map.class).consumeWith(result -> { + List responseBody = result.getResponseBody(); assertThat(responseBody).isNotEmpty(); + assertThat(responseBody).contains( + Map.of("href", "/actuator/gateway/", "methods", + List.of("GET")), + Map.of("href", "/actuator/gateway/globalfilters", "methods", + List.of("GET")), + Map.of("href", "/actuator/gateway/refresh", "methods", + List.of("POST")), + Map.of("href", "/actuator/gateway/routedefinitions", + "methods", List.of("GET")), + Map.of("href", "/actuator/gateway/routefilters", "methods", + List.of("GET")), + Map.of("href", "/actuator/gateway/routepredicates", "methods", + List.of("GET")), + Map.of("href", "/actuator/gateway/routes", "methods", + List.of("POST", "GET")), + Map.of("href", "/actuator/gateway/routes/test-service", + "methods", List.of("POST", "DELETE", "GET")), + Map.of("href", "/actuator/gateway/routes/route_with_metadata", + "methods", List.of("POST", "DELETE", "GET"))); }); } From 84c351a864822182090c9f0455531e7b57cd034a Mon Sep 17 00:00:00 2001 From: Fredrich Ombico Date: Tue, 5 Dec 2023 13:49:12 -0500 Subject: [PATCH 4/5] Refactor to use the actuator path set in properties - Also cleaned up code and warnings --- .../AbstractGatewayControllerEndpoint.java | 66 ++++++++++--------- .../actuate/GatewayControllerEndpoint.java | 8 ++- .../GatewayLegacyControllerEndpoint.java | 5 +- .../config/GatewayAutoConfiguration.java | 10 +-- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java index ab521961..f946b16d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java @@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -71,8 +72,6 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis private static final Log log = LogFactory.getLog(GatewayControllerEndpoint.class); - private static final String ENDPOINT_PREFIX = "/actuator/gateway"; - protected RouteDefinitionLocator routeDefinitionLocator; protected List globalFilters; @@ -88,25 +87,55 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis protected ApplicationEventPublisher publisher; + protected WebEndpointProperties webEndpointProperties; + + private final SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); + public AbstractGatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List globalFilters, List gatewayFilters, List routePredicates, RouteDefinitionWriter routeDefinitionWriter, - RouteLocator routeLocator) { + RouteLocator routeLocator, WebEndpointProperties webEndpointProperties) { this.routeDefinitionLocator = routeDefinitionLocator; this.globalFilters = globalFilters; this.GatewayFilters = gatewayFilters; this.routePredicates = routePredicates; this.routeDefinitionWriter = routeDefinitionWriter; this.routeLocator = routeLocator; + this.webEndpointProperties = webEndpointProperties; + } + + @GetMapping("/") + Mono> getEndpoints() { + List endpoints = mergeEndpoints( + getAvailableEndpointsForClass(AbstractGatewayControllerEndpoint.class.getName()), + getAvailableEndpointsForClass(GatewayControllerEndpoint.class.getName())); + + return Flux.fromIterable(endpoints).map(p -> p) + .flatMap(path -> this.routeLocator.getRoutes().map(r -> generateHref(r, path)).distinct().collectList() + .flatMapMany(Flux::fromIterable)) + .distinct() // Ensure overall uniqueness + .collectList(); + } + + private List mergeEndpoints(List listA, + List listB) { + Map> mergedMap = new HashMap<>(); + + Stream.concat(listA.stream(), listB.stream()).forEach(e -> mergedMap + .computeIfAbsent(e.getHref(), k -> new ArrayList<>()).addAll(Arrays.asList(e.getMethods()))); + + return mergedMap.entrySet().stream().map(entry -> new GatewayEndpointInfo(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); } private List getAvailableEndpointsForClass(String className) { try { - MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(className); + MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader(className); Set annotatedMethods = metadataReader.getAnnotationMetadata() .getAnnotatedMethods(RequestMapping.class.getName()); - return annotatedMethods.stream().map(method -> new GatewayEndpointInfo(ENDPOINT_PREFIX + String gatewayActuatorPath = webEndpointProperties.getBasePath() + "/gateway"; + return annotatedMethods.stream().map(method -> new GatewayEndpointInfo(gatewayActuatorPath + ((String[]) method.getAnnotationAttributes(RequestMapping.class.getName()).get("path"))[0], ((RequestMethod[]) method.getAnnotationAttributes(RequestMapping.class.getName()).get("method"))[0] .name())) @@ -118,35 +147,10 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis } } - public static List mergeEndpoints(List listA, - List listB) { - Map> mergedMap = new HashMap<>(); - - Stream.concat(listA.stream(), listB.stream()).forEach(e -> mergedMap - .computeIfAbsent(e.getHref(), k -> new ArrayList<>()).addAll(Arrays.asList(e.getMethods()))); - - return mergedMap.entrySet().stream().map(entry -> new GatewayEndpointInfo(entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); - } - - GatewayEndpointInfo generateHref(Route r, GatewayEndpointInfo path) { + private GatewayEndpointInfo generateHref(Route r, GatewayEndpointInfo path) { return new GatewayEndpointInfo(path.getHref().replace("{id}", r.getId()), Arrays.asList(path.getMethods())); } - @GetMapping("/") - public Mono> getEndpoints() { - List endpoints = mergeEndpoints( - getAvailableEndpointsForClass(AbstractGatewayControllerEndpoint.class.getName()), - getAvailableEndpointsForClass(GatewayControllerEndpoint.class.getName())); - - return Flux.fromIterable(endpoints).map(p -> p) - .flatMap(path -> this.routeLocator.getRoutes().map(r -> generateHref(r, path)).distinct().collectList() - .flatMapMany(Flux::fromIterable)) - .distinct() // Ensure overall uniqueness - .collectList(); - - } - @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpoint.java index 109f2888..34553f86 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpoint.java @@ -24,6 +24,7 @@ import java.util.Map; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -47,9 +48,10 @@ public class GatewayControllerEndpoint extends AbstractGatewayControllerEndpoint public GatewayControllerEndpoint(List globalFilters, List gatewayFilters, List routePredicates, RouteDefinitionWriter routeDefinitionWriter, - RouteLocator routeLocator, RouteDefinitionLocator routeDefinitionLocator) { - super(routeDefinitionLocator, globalFilters, gatewayFilters, routePredicates, routeDefinitionWriter, - routeLocator); + RouteLocator routeLocator, RouteDefinitionLocator routeDefinitionLocator, + WebEndpointProperties webEndpointProperties) { + super(routeDefinitionLocator, globalFilters, gatewayFilters, routePredicates, + routeDefinitionWriter, routeLocator, webEndpointProperties); } @GetMapping("/routedefinitions") diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayLegacyControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayLegacyControllerEndpoint.java index 5e2064cb..32f9b184 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayLegacyControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/GatewayLegacyControllerEndpoint.java @@ -23,6 +23,7 @@ import java.util.Map; import reactor.core.publisher.Mono; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -47,9 +48,9 @@ public class GatewayLegacyControllerEndpoint extends AbstractGatewayControllerEn public GatewayLegacyControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List globalFilters, List gatewayFilterFactories, List routePredicates, RouteDefinitionWriter routeDefinitionWriter, - RouteLocator routeLocator) { + RouteLocator routeLocator, WebEndpointProperties webEndpointProperties) { super(routeDefinitionLocator, globalFilters, gatewayFilterFactories, routePredicates, routeDefinitionWriter, - routeLocator); + routeLocator, webEndpointProperties); } @GetMapping("/routes") diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 534277df..2da24fe6 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -40,6 +40,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; @@ -817,9 +818,9 @@ public class GatewayAutoConfiguration { public GatewayControllerEndpoint gatewayControllerEndpoint(List globalFilters, List gatewayFilters, List routePredicates, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator, - RouteDefinitionLocator routeDefinitionLocator) { + RouteDefinitionLocator routeDefinitionLocator, WebEndpointProperties webEndpointProperties) { return new GatewayControllerEndpoint(globalFilters, gatewayFilters, routePredicates, routeDefinitionWriter, - routeLocator, routeDefinitionLocator); + routeLocator, routeDefinitionLocator, webEndpointProperties); } @Bean @@ -828,9 +829,10 @@ public class GatewayAutoConfiguration { public GatewayLegacyControllerEndpoint gatewayLegacyControllerEndpoint( RouteDefinitionLocator routeDefinitionLocator, List globalFilters, List gatewayFilters, List routePredicates, - RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) { + RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator, + WebEndpointProperties webEndpointProperties) { return new GatewayLegacyControllerEndpoint(routeDefinitionLocator, globalFilters, gatewayFilters, - routePredicates, routeDefinitionWriter, routeLocator); + routePredicates, routeDefinitionWriter, routeLocator, webEndpointProperties); } } From 7249dcc677dde4edaf97a112c512213939f9245c Mon Sep 17 00:00:00 2001 From: Fredrich Ombico Date: Tue, 5 Dec 2023 15:52:22 -0500 Subject: [PATCH 5/5] Deprecate constructor and create a new one with injected WebEndpointProperties - the classes extending this class, `GatewayControllerEndpoint` and `GatewayLegacyControllerEndpoint`, use the new constructor that handles the base path being overridden - any other classes using the deprecated constructor would use the fixed base path `/actuator` --- .../actuate/AbstractGatewayControllerEndpoint.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java index f946b16d..47214e00 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java @@ -91,6 +91,15 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis private final SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); + @Deprecated + public AbstractGatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, + List globalFilters, List gatewayFilters, + List routePredicates, RouteDefinitionWriter routeDefinitionWriter, + RouteLocator routeLocator) { + this(routeDefinitionLocator, globalFilters, gatewayFilters, routePredicates, + routeDefinitionWriter, routeLocator, new WebEndpointProperties()); + } + public AbstractGatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List globalFilters, List gatewayFilters, List routePredicates, RouteDefinitionWriter routeDefinitionWriter,