From 51548b07c842d51104886fc3966769fcdd7ca15a Mon Sep 17 00:00:00 2001 From: spencergibb Date: Mon, 14 Apr 2025 17:40:19 -0400 Subject: [PATCH] Allow bean registration of server-webmcv components This replaces the spring.factories mechanism. Fixes gh-3250 --- .../GatewayServerMvcAutoConfiguration.java | 9 +- .../GatewayMvcAotRuntimeHintsRegistrar.java | 4 +- .../config/RouterFunctionHolderFactory.java | 83 +++++++++---- ...lier.java => FilterAutoConfiguration.java} | 35 +++--- .../mvc/handler/DefaultHandlerSupplier.java | 113 ------------------ .../HandlerFunctionAutoConfiguration.java | 93 ++++++++++++++ .../handler/HandlerFunctionDefinition.java | 45 +++++++ .../main/resources/META-INF/spring.factories | 4 - ...ot.autoconfigure.AutoConfiguration.imports | 2 + 9 files changed, 222 insertions(+), 166 deletions(-) rename spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/{LoadBalancerHandlerSupplier.java => FilterAutoConfiguration.java} (52%) delete mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java create mode 100644 spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index dabf7d2d..00cecf8c 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -18,6 +18,7 @@ package org.springframework.cloud.gateway.server.mvc; import java.util.Map; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -35,6 +36,7 @@ import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcAotRuntimeH import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar; import org.springframework.cloud.gateway.server.mvc.config.RouterFunctionHolderFactory; +import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.filter.FormFilter; import org.springframework.cloud.gateway.server.mvc.filter.ForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.HttpHeadersFilter.RequestHttpHeadersFilter; @@ -47,6 +49,7 @@ import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNorma import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilterProperties; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration; import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchange; import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction; import org.springframework.cloud.gateway.server.mvc.handler.RestClientProxyExchange; @@ -70,7 +73,7 @@ import org.springframework.web.client.RestClient; * @author Jürgen Wißkirchen */ @AutoConfiguration(after = { HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class, - RestClientAutoConfiguration.class }) + RestClientAutoConfiguration.class, FilterAutoConfiguration.class, HandlerFunctionAutoConfiguration.class }) @ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true) @Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class) @ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class) @@ -83,8 +86,8 @@ public class GatewayServerMvcAutoConfiguration { } @Bean - public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env) { - return new RouterFunctionHolderFactory(env); + public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env, BeanFactory beanFactory) { + return new RouterFunctionHolderFactory(env, beanFactory); } @Bean diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java index e4482d3a..08a879c1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcAotRuntimeHintsRegistrar.java @@ -31,7 +31,6 @@ import org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctio import org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions; -import org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerHandlerSupplier; import org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions; import org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions; import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions; @@ -46,8 +45,9 @@ import org.springframework.util.ClassUtils; */ public class GatewayMvcAotRuntimeHintsRegistrar implements RuntimeHintsRegistrar { + // TODO: fix AOT HINTS private static final Set> FUNCTION_PROVIDERS = Set.of(HandlerFunctions.class, - LoadBalancerHandlerSupplier.class, FilterFunctions.class, BeforeFilterFunctions.class, + /* LoadBalancerHandlerSupplier.class, */ FilterFunctions.class, BeforeFilterFunctions.class, AfterFilterFunctions.class, TokenRelayFilterFunctions.class, BodyFilterFunctions.class, CircuitBreakerFilterFunctions.class, GatewayRouterFunctions.class, LoadBalancerFilterFunctions.class, GatewayRequestPredicates.class, Bucket4jFilterFunctions.class); diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java index 6bc52a52..babf4ef1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java @@ -28,10 +28,14 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.handler.IgnoreTopLevelConverterNotFoundBindHandler; @@ -41,6 +45,7 @@ import org.springframework.cloud.gateway.server.mvc.common.Configurable; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.cloud.gateway.server.mvc.filter.FilterDiscoverer; import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionDefinition; import org.springframework.cloud.gateway.server.mvc.invoke.InvocationContext; import org.springframework.cloud.gateway.server.mvc.invoke.OperationArgumentResolver; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; @@ -102,8 +107,16 @@ public class RouterFunctionHolderFactory { private final ParameterValueMapper parameterValueMapper = new ConversionServiceParameterValueMapper(); + private final BeanFactory beanFactory; + + @Deprecated public RouterFunctionHolderFactory(Environment env) { + this(env, null); + } + + public RouterFunctionHolderFactory(Environment env, BeanFactory beanFactory) { this.env = env; + this.beanFactory = beanFactory; } /** @@ -153,37 +166,57 @@ public class RouterFunctionHolderFactory { // TODO: cache? // translate handlerFunction String scheme = routeProperties.getUri().getScheme(); - Map handlerArgs = new HashMap<>(); - Optional handlerOperationMethod = findOperation(handlerOperations, - scheme.toLowerCase(Locale.ROOT), handlerArgs); - if (handlerOperationMethod.isEmpty()) { - // single RouteProperties param - handlerArgs.clear(); - String routePropsKey = StringUtils.uncapitalize(RouteProperties.class.getSimpleName()); - handlerArgs.put(routePropsKey, routeProperties); - handlerOperationMethod = findOperation(handlerOperations, scheme.toLowerCase(Locale.ROOT), handlerArgs); - if (handlerOperationMethod.isEmpty()) { - throw new IllegalStateException("Unable to find HandlerFunction for scheme: " + scheme); - } - } - NormalizedOperationMethod normalizedOpMethod = handlerOperationMethod.get(); - Object response = invokeOperation(normalizedOpMethod, normalizedOpMethod.getNormalizedArgs()); - HandlerFunction handlerFunction = null; // filters added by HandlerDiscoverer need to go last, so save them + HandlerFunction handlerFunction = null; List> lowerPrecedenceFilters = new ArrayList<>(); List> higherPrecedenceFilters = new ArrayList<>(); - if (response instanceof HandlerFunction) { - handlerFunction = (HandlerFunction) response; - } - else if (response instanceof HandlerDiscoverer.Result result) { - handlerFunction = result.getHandlerFunction(); - lowerPrecedenceFilters.addAll(result.getLowerPrecedenceFilters()); - higherPrecedenceFilters.addAll(result.getHigherPrecedenceFilters()); + + if (beanFactory != null) { + try { + // TODO: configurable bean name? + String name = scheme + "HandlerFunctionDefinition"; + Function factory = beanFactory.getBean(name, Function.class); + HandlerFunctionDefinition definition = (HandlerFunctionDefinition) factory.apply(routeProperties); + handlerFunction = definition.handlerFunction(); + lowerPrecedenceFilters.addAll(definition.lowerPrecedenceFilters()); + higherPrecedenceFilters.addAll(definition.higherPrecedenceFilters()); + } + catch (NoSuchBeanDefinitionException | BeanNotOfRequiredTypeException | ClassCastException e) { + log.trace(LogMessage.format("Unable to locate bean of HandlerFunction for scheme %s", scheme), e); + } } + if (handlerFunction == null) { - throw new IllegalStateException( - "Unable to find HandlerFunction for scheme: " + scheme + " and response " + response); + Map handlerArgs = new HashMap<>(); + Optional handlerOperationMethod = findOperation(handlerOperations, + scheme.toLowerCase(Locale.ROOT), handlerArgs); + if (handlerOperationMethod.isEmpty()) { + // single RouteProperties param + handlerArgs.clear(); + String routePropsKey = StringUtils.uncapitalize(RouteProperties.class.getSimpleName()); + handlerArgs.put(routePropsKey, routeProperties); + handlerOperationMethod = findOperation(handlerOperations, scheme.toLowerCase(Locale.ROOT), handlerArgs); + if (handlerOperationMethod.isEmpty()) { + throw new IllegalStateException("Unable to find HandlerFunction for scheme: " + scheme); + } + } + + NormalizedOperationMethod normalizedOpMethod = handlerOperationMethod.get(); + Object response = invokeOperation(normalizedOpMethod, normalizedOpMethod.getNormalizedArgs()); + + if (response instanceof HandlerFunction) { + handlerFunction = (HandlerFunction) response; + } + else if (response instanceof HandlerDiscoverer.Result result) { + handlerFunction = result.getHandlerFunction(); + lowerPrecedenceFilters.addAll(result.getLowerPrecedenceFilters()); + higherPrecedenceFilters.addAll(result.getHigherPrecedenceFilters()); + } + if (handlerFunction == null) { + throw new IllegalStateException( + "Unable to find HandlerFunction for scheme: " + scheme + " and response " + response); + } } // translate predicates diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java similarity index 52% rename from spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java rename to spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java index c2a0ad58..c2cd62a1 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/LoadBalancerHandlerSupplier.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 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. @@ -16,32 +16,29 @@ package org.springframework.cloud.gateway.server.mvc.filter; -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; +import java.util.function.Function; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; -import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer; +import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionDefinition; import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions; -import org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; -public class LoadBalancerHandlerSupplier implements HandlerSupplier { +@AutoConfiguration +public class FilterAutoConfiguration { - @Override - public Collection get() { - return Arrays.asList(getClass().getMethods()); - } + @Configuration(proxyBeanMethods = false) + static class LoadBalancerHandlerConfiguration { - public static HandlerDiscoverer.Result lb(RouteProperties routeProperties) { - return lb(routeProperties.getUri()); - } + @Bean + public Function lbHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("lb", HandlerFunctions.http(), + Collections.emptyList(), + Collections.singletonList(LoadBalancerFilterFunctions.lb(routeProperties.getUri().getHost()))); + } - public static HandlerDiscoverer.Result lb(URI uri) { - // TODO: how to do something other than http - return new HandlerDiscoverer.Result(HandlerFunctions.http(), Collections.emptyList(), - Collections.singletonList(LoadBalancerFilterFunctions.lb(uri.getHost()))); } } diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java deleted file mode 100644 index 0adc142e..00000000 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultHandlerSupplier.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2013-2025 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.server.mvc.handler; - -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; -import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; -import org.springframework.web.servlet.function.HandlerFilterFunction; -import org.springframework.web.servlet.function.HandlerFunction; -import org.springframework.web.servlet.function.ServerResponse; - -class DefaultHandlerSupplier implements HandlerSupplier { - - @Override - public Collection get() { - return Arrays.asList(getClass().getMethods()); - } - - public static HandlerDiscoverer.Result fn(RouteProperties routeProperties) { - // fn:fnName - return fn(routeProperties.getUri().getSchemeSpecificPart()); - } - - public static HandlerDiscoverer.Result fn(String functionName) { - return new HandlerDiscoverer.Result(HandlerFunctions.fn(functionName), Collections.emptyList(), - Collections.emptyList()); - } - - public static HandlerDiscoverer.Result forward(RouteProperties routeProperties) { - return forward(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result forward(String id, URI uri) { - return new HandlerDiscoverer.Result(HandlerFunctions.forward(uri.getPath()), Collections.emptyList()); - } - - public static HandlerDiscoverer.Result http(RouteProperties routeProperties) { - return http(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result http(String id, URI uri) { - HandlerFunction http = HandlerFunctions.http(); - return getResult(id, uri, http); - } - - public static HandlerDiscoverer.Result https(RouteProperties routeProperties) { - return https(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result https(String id, URI uri) { - return getResult(id, uri, HandlerFunctions.https()); - } - - public static HandlerDiscoverer.Result no(RouteProperties routeProperties) { - return no(routeProperties.getId(), routeProperties.getUri()); - } - - public static HandlerDiscoverer.Result no(String id, URI uri) { - return getResult(id, uri, HandlerFunctions.no()); - } - - // for properties - public static HandlerDiscoverer.Result stream(RouteProperties routeProperties) { - // stream:bindingName - return stream(routeProperties.getUri().getSchemeSpecificPart()); - } - - public static HandlerDiscoverer.Result stream(String bindingName) { - return new HandlerDiscoverer.Result(HandlerFunctions.stream(bindingName), Collections.emptyList(), - Collections.emptyList()); - } - - private static HandlerDiscoverer.Result getResult(String id, URI uri, - HandlerFunction handlerFunction) { - HandlerFilterFunction setId = setIdFilter(id); - HandlerFilterFunction setRequest = setRequestUrlFilter(uri); - return new HandlerDiscoverer.Result(handlerFunction, Arrays.asList(setId, setRequest), Collections.emptyList()); - } - - private static HandlerFilterFunction setIdFilter(String id) { - return (request, next) -> { - MvcUtils.setRouteId(request, id); - return next.handle(request); - }; - } - - private static HandlerFilterFunction setRequestUrlFilter(URI uri) { - return (request, next) -> { - MvcUtils.setRequestUrl(request, uri); - return next.handle(request); - }; - } - -} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java new file mode 100644 index 00000000..3e4d3781 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java @@ -0,0 +1,93 @@ +/* + * Copyright 2013-2025 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.server.mvc.handler; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Function; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; +import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.function.HandlerFilterFunction; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; + +@AutoConfiguration +public class HandlerFunctionAutoConfiguration { + + @Bean + public Function fnHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("fn", + HandlerFunctions.fn(routeProperties.getUri().getSchemeSpecificPart())); + } + + @Bean + public Function forwardHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("forward", + HandlerFunctions.forward(routeProperties.getUri().getPath())); + } + + @Bean + public Function httpHandlerFunctionDefinition() { + return routeProperties -> getResult("http", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.http()); + } + + @Bean + public Function httpsHandlerFunctionDefinition() { + return routeProperties -> getResult("https", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.https()); + } + + @Bean + public Function noHandlerFunctionDefinition() { + return routeProperties -> getResult("no", routeProperties.getId(), routeProperties.getUri(), + HandlerFunctions.no()); + } + + @Bean + public Function streamHandlerFunctionDefinition() { + return routeProperties -> new HandlerFunctionDefinition.Default("stream", + HandlerFunctions.stream(routeProperties.getUri().getSchemeSpecificPart())); + } + + private static HandlerFunctionDefinition getResult(String scheme, String id, URI uri, + HandlerFunction handlerFunction) { + HandlerFilterFunction setId = setIdFilter(id); + HandlerFilterFunction setRequest = setRequestUrlFilter(uri); + return new HandlerFunctionDefinition.Default(scheme, handlerFunction, Arrays.asList(setId, setRequest), + Collections.emptyList()); + } + + private static HandlerFilterFunction setIdFilter(String id) { + return (request, next) -> { + MvcUtils.setRouteId(request, id); + return next.handle(request); + }; + } + + private static HandlerFilterFunction setRequestUrlFilter(URI uri) { + return (request, next) -> { + MvcUtils.setRequestUrl(request, uri); + return next.handle(request); + }; + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java new file mode 100644 index 00000000..12d79fe6 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionDefinition.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013-2025 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.server.mvc.handler; + +import java.util.Collections; +import java.util.List; + +import org.springframework.web.servlet.function.HandlerFilterFunction; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; + +public interface HandlerFunctionDefinition { + + HandlerFunction handlerFunction(); + + List> lowerPrecedenceFilters(); + + List> higherPrecedenceFilters(); + + record Default(String scheme, HandlerFunction handlerFunction, + List> lowerPrecedenceFilters, + List> higherPrecedenceFilters) + implements + HandlerFunctionDefinition { + + public Default(String scheme, HandlerFunction handlerFunction) { + this(scheme, handlerFunction, Collections.emptyList(), Collections.emptyList()); + } + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories index b7002f15..452cfce5 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring.factories @@ -22,10 +22,6 @@ org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\ org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions.FilterSupplier,\ org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions.FilterSupplier -org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier=\ - org.springframework.cloud.gateway.server.mvc.handler.DefaultHandlerSupplier,\ - org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerHandlerSupplier - org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\ org.springframework.cloud.gateway.server.mvc.predicate.MvcPredicateSupplier,\ org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.PredicateSupplier diff --git a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 94282943..2c2f8596 100644 --- a/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-cloud-gateway-server-mvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,5 +1,7 @@ org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration org.springframework.cloud.gateway.server.mvc.GatewayMvcClassPathWarningAutoConfiguration +org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration +org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionAutoConfiguration org.springframework.cloud.gateway.server.mvc.handler.GatewayMultipartAutoConfiguration org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration org.springframework.cloud.gateway.server.mvc.config.DefaultFunctionConfiguration \ No newline at end of file