Allow bean registration of server-webmcv components (#3763)
* Allow bean registration of server-webmcv components This replaces the spring.factories mechanism. * Adds support for loading FilterSuppliers via beans * Adds support for loading PredicateSuppliers via beans * Use beanFactory conversionService Fixes gh-3250
This commit is contained in:
@@ -240,13 +240,12 @@ The above route will add a `X-Response-Id` header to the response. Note the use
|
||||
|
||||
== How To Register Custom Predicates and Filters for Configuration
|
||||
|
||||
To use custom Predicates and Filters in external configuration you need to create a special Supplier class and register it in `META-INF/spring.factories`.
|
||||
To use custom Predicates and Filters in external configuration you need to create a special Supplier class and register it a bean in the application context.
|
||||
|
||||
=== Registering Custom Predicates
|
||||
|
||||
To register custom predicates you need to implement `PredicateSupplier`. The `PredicateDiscoverer` looks for static methods that return `RequestPredicates` to register.
|
||||
|
||||
|
||||
SampleFilterSupplier.java
|
||||
[source,java]
|
||||
----
|
||||
@@ -254,7 +253,6 @@ package com.example;
|
||||
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier;
|
||||
|
||||
@Configuration
|
||||
class SamplePredicateSupplier implements PredicateSupplier {
|
||||
|
||||
@Override
|
||||
@@ -265,7 +263,24 @@ class SamplePredicateSupplier implements PredicateSupplier {
|
||||
}
|
||||
----
|
||||
|
||||
You then need to add the class in `META-INF/spring.factories`.
|
||||
To register the `PredicateSupplier` for use in config files, you then need to add the class as a bean as in the example below:
|
||||
|
||||
.PredicateConfiguration.java
|
||||
[source,java]
|
||||
----
|
||||
package com.example;
|
||||
|
||||
@Configuration
|
||||
class PredicateConfiguration {
|
||||
|
||||
@Bean
|
||||
public SamplePredicateSupplier samplePredicateSupplier() {
|
||||
return new SamplePredicateSupplier();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The requirement to add the class to `META-INF/spring.factories` is deprecated and will be removed in the next major release.
|
||||
|
||||
.META-INF/spring.factories
|
||||
[source]
|
||||
@@ -285,7 +300,6 @@ package com.example;
|
||||
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.SimpleFilterSupplier;
|
||||
|
||||
@Configuration
|
||||
class SampleFilterSupplier extends SimpleFilterSupplier {
|
||||
|
||||
public SampleFilterSupplier() {
|
||||
@@ -294,7 +308,24 @@ class SampleFilterSupplier extends SimpleFilterSupplier {
|
||||
}
|
||||
----
|
||||
|
||||
You then need to add the class in `META-INF/spring.factories`.
|
||||
To register the `FilterSupplier` for use in config files, you then need to add the class as a bean as in the example below:
|
||||
|
||||
.FilterConfiguration.java
|
||||
[source,java]
|
||||
----
|
||||
package com.example;
|
||||
|
||||
@Configuration
|
||||
class FilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public SampleFilterSupplier sampleFilterSupplier() {
|
||||
return new SampleFilterSupplier();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The requirement to add the class to `META-INF/spring.factories` is deprecated and will be removed in the next major release.
|
||||
|
||||
.META-INF/spring.factories
|
||||
[source]
|
||||
|
||||
@@ -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,8 @@ 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.FilterBeanFactoryDiscoverer;
|
||||
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,9 +50,12 @@ 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;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateBeanFactoryDiscoverer;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateDiscoverer;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -70,7 +76,8 @@ 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,
|
||||
PredicateAutoConfiguration.class })
|
||||
@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true)
|
||||
@Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class)
|
||||
@ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class)
|
||||
@@ -83,8 +90,11 @@ public class GatewayServerMvcAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env) {
|
||||
return new RouterFunctionHolderFactory(env);
|
||||
public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env, BeanFactory beanFactory,
|
||||
FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer,
|
||||
PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer) {
|
||||
return new RouterFunctionHolderFactory(env, beanFactory, filterBeanFactoryDiscoverer,
|
||||
predicateBeanFactoryDiscoverer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
|
||||
public abstract class BeanFactoryGatewayDiscoverer extends AbstractGatewayDiscoverer {
|
||||
|
||||
protected final BeanFactory beanFactory;
|
||||
|
||||
protected BeanFactoryGatewayDiscoverer(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> List<T> loadSuppliers(Class<T> supplierClass) {
|
||||
ObjectProvider<T> beanProvider = beanFactory.getBeanProvider(supplierClass);
|
||||
return beanProvider.orderedStream().toList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,9 +29,9 @@ import org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.BodyFilterFunctions;
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions;
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions;
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration;
|
||||
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,11 +46,12 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class GatewayMvcAotRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
|
||||
|
||||
// TODO: fix AOT HINTS
|
||||
private static final Set<Class<?>> FUNCTION_PROVIDERS = Set.of(HandlerFunctions.class,
|
||||
LoadBalancerHandlerSupplier.class, FilterFunctions.class, BeforeFilterFunctions.class,
|
||||
AfterFilterFunctions.class, TokenRelayFilterFunctions.class, BodyFilterFunctions.class,
|
||||
CircuitBreakerFilterFunctions.class, GatewayRouterFunctions.class, LoadBalancerFilterFunctions.class,
|
||||
GatewayRequestPredicates.class, Bucket4jFilterFunctions.class);
|
||||
FilterAutoConfiguration.LoadBalancerHandlerConfiguration.class, FilterFunctions.class,
|
||||
BeforeFilterFunctions.class, AfterFilterFunctions.class, TokenRelayFilterFunctions.class,
|
||||
BodyFilterFunctions.class, CircuitBreakerFilterFunctions.class, GatewayRouterFunctions.class,
|
||||
LoadBalancerFilterFunctions.class, GatewayRequestPredicates.class, Bucket4jFilterFunctions.class);
|
||||
|
||||
private static final Set<Class<?>> PROPERTIES = Set.of(FilterProperties.class, PredicateProperties.class,
|
||||
RouteProperties.class);
|
||||
|
||||
@@ -28,10 +28,15 @@ 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.beans.factory.config.ConfigurableBeanFactory;
|
||||
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;
|
||||
@@ -39,8 +44,10 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS
|
||||
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
|
||||
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.FilterBeanFactoryDiscoverer;
|
||||
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;
|
||||
@@ -49,10 +56,13 @@ import org.springframework.cloud.gateway.server.mvc.invoke.ParameterValueMapper;
|
||||
import org.springframework.cloud.gateway.server.mvc.invoke.convert.ConversionServiceParameterValueMapper;
|
||||
import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod;
|
||||
import org.springframework.cloud.gateway.server.mvc.invoke.reflect.ReflectiveOperationInvoker;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateBeanFactoryDiscoverer;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateDiscoverer;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.function.HandlerFilterFunction;
|
||||
@@ -102,8 +112,37 @@ public class RouterFunctionHolderFactory {
|
||||
|
||||
private final ParameterValueMapper parameterValueMapper = new ConversionServiceParameterValueMapper();
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer;
|
||||
|
||||
private final PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
@Deprecated
|
||||
public RouterFunctionHolderFactory(Environment env) {
|
||||
this(env, null, null, null);
|
||||
}
|
||||
|
||||
public RouterFunctionHolderFactory(Environment env, BeanFactory beanFactory,
|
||||
FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer,
|
||||
PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer) {
|
||||
this.env = env;
|
||||
this.beanFactory = beanFactory;
|
||||
this.filterBeanFactoryDiscoverer = filterBeanFactoryDiscoverer;
|
||||
this.predicateBeanFactoryDiscoverer = predicateBeanFactoryDiscoverer;
|
||||
if (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) {
|
||||
if (configurableBeanFactory.getConversionService() != null) {
|
||||
this.conversionService = configurableBeanFactory.getConversionService();
|
||||
}
|
||||
else {
|
||||
this.conversionService = DefaultConversionService.getSharedInstance();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.conversionService = DefaultConversionService.getSharedInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,41 +192,65 @@ public class RouterFunctionHolderFactory {
|
||||
// TODO: cache?
|
||||
// translate handlerFunction
|
||||
String scheme = routeProperties.getUri().getScheme();
|
||||
Map<String, Object> handlerArgs = new HashMap<>();
|
||||
Optional<NormalizedOperationMethod> 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<ServerResponse> handlerFunction = null;
|
||||
|
||||
// filters added by HandlerDiscoverer need to go last, so save them
|
||||
HandlerFunction<ServerResponse> handlerFunction = null;
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> lowerPrecedenceFilters = new ArrayList<>();
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> higherPrecedenceFilters = new ArrayList<>();
|
||||
if (response instanceof HandlerFunction<?>) {
|
||||
handlerFunction = (HandlerFunction<ServerResponse>) 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<String, Object> handlerArgs = new HashMap<>();
|
||||
Optional<NormalizedOperationMethod> 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<ServerResponse>) 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
|
||||
MultiValueMap<String, OperationMethod> predicateOperations = predicateDiscoverer.getOperations();
|
||||
MultiValueMap<String, OperationMethod> predicateOperations = new LinkedMultiValueMap<>();
|
||||
if (predicateBeanFactoryDiscoverer != null) {
|
||||
predicateOperations.addAll(predicateBeanFactoryDiscoverer.getOperations());
|
||||
}
|
||||
predicateOperations.addAll(predicateDiscoverer.getOperations());
|
||||
final AtomicReference<RequestPredicate> predicate = new AtomicReference<>();
|
||||
|
||||
routeProperties.getPredicates().forEach(predicateProperties -> {
|
||||
@@ -214,7 +277,11 @@ public class RouterFunctionHolderFactory {
|
||||
lowerPrecedenceFilters.forEach(builder::filter);
|
||||
|
||||
// translate filters
|
||||
MultiValueMap<String, OperationMethod> filterOperations = filterDiscoverer.getOperations();
|
||||
MultiValueMap<String, OperationMethod> filterOperations = new LinkedMultiValueMap<>();
|
||||
if (filterBeanFactoryDiscoverer != null) {
|
||||
filterOperations.addAll(filterBeanFactoryDiscoverer.getOperations());
|
||||
}
|
||||
filterOperations.addAll(filterDiscoverer.getOperations());
|
||||
routeProperties.getFilters().forEach(filterProperties -> {
|
||||
Map<String, Object> args = new LinkedHashMap<>(filterProperties.getArgs());
|
||||
translate(filterOperations, filterProperties.getName(), args, HandlerFilterFunction.class, builder::filter);
|
||||
@@ -295,7 +362,7 @@ public class RouterFunctionHolderFactory {
|
||||
return operationInvoker.invoke(context);
|
||||
}
|
||||
|
||||
private static Object bindConfigurable(OperationMethod operationMethod, Map<String, Object> args,
|
||||
private Object bindConfigurable(OperationMethod operationMethod, Map<String, Object> args,
|
||||
OperationParameter operationParameter) {
|
||||
Class<?> configurableType = operationParameter.getType();
|
||||
Configurable configurable = operationMethod.getMethod().getAnnotation(Configurable.class);
|
||||
@@ -305,8 +372,8 @@ public class RouterFunctionHolderFactory {
|
||||
Bindable<?> bindable = Bindable.of(configurableType);
|
||||
List<ConfigurationPropertySource> propertySources = Collections
|
||||
.singletonList(new MapConfigurationPropertySource(args));
|
||||
// TODO: potentially deal with conversion service
|
||||
Binder binder = new Binder(propertySources, null, DefaultConversionService.getSharedInstance());
|
||||
|
||||
Binder binder = new Binder(propertySources, null, conversionService);
|
||||
Object config = binder.bindOrCreate("", bindable, new IgnoreTopLevelConverterNotFoundBindHandler());
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.filter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.github.bucket4j.BucketConfiguration;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||
import org.springframework.cloud.gateway.server.mvc.config.RouteProperties;
|
||||
import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctionDefinition;
|
||||
import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
|
||||
@AutoConfiguration
|
||||
public class FilterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer(BeanFactory beanFactory) {
|
||||
return new FilterBeanFactoryDiscoverer(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterFunctions.FilterSupplier filterFunctionsSupplier() {
|
||||
return new FilterFunctions.FilterSupplier();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(BucketConfiguration.class)
|
||||
static class Bucket4jFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public Bucket4jFilterFunctions.FilterSupplier bucket4jFilterFunctionsSupplier() {
|
||||
return new Bucket4jFilterFunctions.FilterSupplier();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(CircuitBreaker.class)
|
||||
static class CircuitBreakerFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public CircuitBreakerFilterFunctions.FilterSupplier circuitBreakerFilterFunctionsSupplier() {
|
||||
return new CircuitBreakerFilterFunctions.FilterSupplier();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(LoadBalancerClient.class)
|
||||
public static class LoadBalancerHandlerConfiguration {
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> lbHandlerFunctionDefinition() {
|
||||
return routeProperties -> new HandlerFunctionDefinition.Default("lb", HandlerFunctions.http(),
|
||||
Collections.emptyList(),
|
||||
Collections.singletonList(LoadBalancerFilterFunctions.lb(routeProperties.getUri().getHost())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RetryTemplate.class)
|
||||
static class RetryFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public RetryFilterFunctions.FilterSupplier retryFilterFunctionsSupplier() {
|
||||
return new RetryFilterFunctions.FilterSupplier();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(OAuth2AuthorizedClient.class)
|
||||
static class TokenRelayFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public TokenRelayFilterFunctions.FilterSupplier tokenRelayFilterFunctionsSupplier() {
|
||||
return new TokenRelayFilterFunctions.FilterSupplier();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.filter;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.gateway.server.mvc.common.BeanFactoryGatewayDiscoverer;
|
||||
import org.springframework.web.servlet.function.HandlerFilterFunction;
|
||||
|
||||
public class FilterBeanFactoryDiscoverer extends BeanFactoryGatewayDiscoverer {
|
||||
|
||||
protected FilterBeanFactoryDiscoverer(BeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discover() {
|
||||
doDiscover(FilterSupplier.class, HandlerFilterFunction.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.filter;
|
||||
|
||||
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.config.RouteProperties;
|
||||
import org.springframework.cloud.gateway.server.mvc.handler.HandlerDiscoverer;
|
||||
import org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions;
|
||||
import org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier;
|
||||
|
||||
public class LoadBalancerHandlerSupplier implements HandlerSupplier {
|
||||
|
||||
@Override
|
||||
public Collection<Method> get() {
|
||||
return Arrays.asList(getClass().getMethods());
|
||||
}
|
||||
|
||||
public static HandlerDiscoverer.Result lb(RouteProperties routeProperties) {
|
||||
return lb(routeProperties.getUri());
|
||||
}
|
||||
|
||||
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())));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Method> 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<ServerResponse> 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<ServerResponse> handlerFunction) {
|
||||
HandlerFilterFunction<ServerResponse, ServerResponse> setId = setIdFilter(id);
|
||||
HandlerFilterFunction<ServerResponse, ServerResponse> setRequest = setRequestUrlFilter(uri);
|
||||
return new HandlerDiscoverer.Result(handlerFunction, Arrays.asList(setId, setRequest), Collections.emptyList());
|
||||
}
|
||||
|
||||
private static HandlerFilterFunction<ServerResponse, ServerResponse> setIdFilter(String id) {
|
||||
return (request, next) -> {
|
||||
MvcUtils.setRouteId(request, id);
|
||||
return next.handle(request);
|
||||
};
|
||||
}
|
||||
|
||||
private static HandlerFilterFunction<ServerResponse, ServerResponse> setRequestUrlFilter(URI uri) {
|
||||
return (request, next) -> {
|
||||
MvcUtils.setRequestUrl(request, uri);
|
||||
return next.handle(request);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<RouteProperties, HandlerFunctionDefinition> fnHandlerFunctionDefinition() {
|
||||
return routeProperties -> new HandlerFunctionDefinition.Default("fn",
|
||||
HandlerFunctions.fn(routeProperties.getUri().getSchemeSpecificPart()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> forwardHandlerFunctionDefinition() {
|
||||
return routeProperties -> new HandlerFunctionDefinition.Default("forward",
|
||||
HandlerFunctions.forward(routeProperties.getUri().getPath()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> httpHandlerFunctionDefinition() {
|
||||
return routeProperties -> getResult("http", routeProperties.getId(), routeProperties.getUri(),
|
||||
HandlerFunctions.http());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> httpsHandlerFunctionDefinition() {
|
||||
return routeProperties -> getResult("https", routeProperties.getId(), routeProperties.getUri(),
|
||||
HandlerFunctions.https());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> noHandlerFunctionDefinition() {
|
||||
return routeProperties -> getResult("no", routeProperties.getId(), routeProperties.getUri(),
|
||||
HandlerFunctions.no());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<RouteProperties, HandlerFunctionDefinition> streamHandlerFunctionDefinition() {
|
||||
return routeProperties -> new HandlerFunctionDefinition.Default("stream",
|
||||
HandlerFunctions.stream(routeProperties.getUri().getSchemeSpecificPart()));
|
||||
}
|
||||
|
||||
private static HandlerFunctionDefinition getResult(String scheme, String id, URI uri,
|
||||
HandlerFunction<ServerResponse> handlerFunction) {
|
||||
HandlerFilterFunction<ServerResponse, ServerResponse> setId = setIdFilter(id);
|
||||
HandlerFilterFunction<ServerResponse, ServerResponse> setRequest = setRequestUrlFilter(uri);
|
||||
return new HandlerFunctionDefinition.Default(scheme, handlerFunction, Arrays.asList(setId, setRequest),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
private static HandlerFilterFunction<ServerResponse, ServerResponse> setIdFilter(String id) {
|
||||
return (request, next) -> {
|
||||
MvcUtils.setRouteId(request, id);
|
||||
return next.handle(request);
|
||||
};
|
||||
}
|
||||
|
||||
private static HandlerFilterFunction<ServerResponse, ServerResponse> setRequestUrlFilter(URI uri) {
|
||||
return (request, next) -> {
|
||||
MvcUtils.setRequestUrl(request, uri);
|
||||
return next.handle(request);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ServerResponse> handlerFunction();
|
||||
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> lowerPrecedenceFilters();
|
||||
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> higherPrecedenceFilters();
|
||||
|
||||
record Default(String scheme, HandlerFunction<ServerResponse> handlerFunction,
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> lowerPrecedenceFilters,
|
||||
List<HandlerFilterFunction<ServerResponse, ServerResponse>> higherPrecedenceFilters)
|
||||
implements
|
||||
HandlerFunctionDefinition {
|
||||
|
||||
public Default(String scheme, HandlerFunction<ServerResponse> handlerFunction) {
|
||||
this(scheme, handlerFunction, Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.predicate;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@AutoConfiguration
|
||||
public class PredicateAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer(BeanFactory beanFactory) {
|
||||
return new PredicateBeanFactoryDiscoverer(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
MvcPredicateSupplier mvcPredicateSupplier() {
|
||||
return new MvcPredicateSupplier();
|
||||
}
|
||||
|
||||
@Bean
|
||||
GatewayRequestPredicates.PredicateSupplier gatewayRequestPredicateSupplier() {
|
||||
return new GatewayRequestPredicates.PredicateSupplier();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.predicate;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.gateway.server.mvc.common.BeanFactoryGatewayDiscoverer;
|
||||
import org.springframework.web.servlet.function.RequestPredicate;
|
||||
|
||||
public class PredicateBeanFactoryDiscoverer extends BeanFactoryGatewayDiscoverer {
|
||||
|
||||
protected PredicateBeanFactoryDiscoverer(BeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discover() {
|
||||
doDiscover(PredicateSupplier.class, RequestPredicate.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,21 +15,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\
|
||||
org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.FilterSupplier,\
|
||||
org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.FilterSupplier,\
|
||||
org.springframework.cloud.gateway.server.mvc.filter.RetryFilterFunctions.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
|
||||
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.cloud.gateway.server.mvc.GatewayServerMvcAutoConfiguration.GatewayHttpClientEnvironmentPostProcessor,\
|
||||
org.springframework.cloud.gateway.server.mvc.common.MultipartEnvironmentPostProcessor
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
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.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration
|
||||
org.springframework.cloud.gateway.server.mvc.config.DefaultFunctionConfiguration
|
||||
@@ -35,6 +35,7 @@ import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
|
||||
import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
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.RemoveContentLengthRequestHeadersFilter;
|
||||
@@ -44,6 +45,8 @@ import org.springframework.cloud.gateway.server.mvc.filter.RemoveHttp2StatusResp
|
||||
import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNormalizationRequestHeadersFilter;
|
||||
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.handler.HandlerFunctionAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -109,7 +112,8 @@ public class GatewayServerMvcAutoConfigurationTests {
|
||||
@Test
|
||||
void filterEnabledPropertiesWork() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(GatewayServerMvcAutoConfiguration.class,
|
||||
.withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class,
|
||||
HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class,
|
||||
HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class,
|
||||
RestClientAutoConfiguration.class, SslAutoConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.gateway.mvc.form-filter.enabled=false",
|
||||
@@ -161,7 +165,8 @@ public class GatewayServerMvcAutoConfigurationTests {
|
||||
@Test
|
||||
void bootHttpClientPropertiesWork() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(GatewayServerMvcAutoConfiguration.class,
|
||||
.withConfiguration(AutoConfigurations.of(FilterAutoConfiguration.class, PredicateAutoConfiguration.class,
|
||||
HandlerFunctionAutoConfiguration.class, GatewayServerMvcAutoConfiguration.class,
|
||||
HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class,
|
||||
RestClientAutoConfiguration.class, SslAutoConfiguration.class))
|
||||
.withPropertyValues("spring.http.client.connect-timeout=1s", "spring.http.client.read-timeout=2s",
|
||||
|
||||
@@ -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.filter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class FilterDiscovererTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
MultiValueMap<String, OperationMethod> operations = new FilterDiscoverer().getOperations();
|
||||
assertThat(operations).isNotEmpty();
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.predicate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.gateway.server.mvc.invoke.reflect.OperationMethod;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class PredicateBeanFactoryDiscovererTests {
|
||||
|
||||
@Autowired
|
||||
PredicateBeanFactoryDiscoverer discoverer;
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
MultiValueMap<String, OperationMethod> operations = discoverer.getOperations();
|
||||
assertThat(operations).isNotEmpty();
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier;
|
||||
import org.springframework.web.servlet.function.RequestPredicate;
|
||||
|
||||
public class TestPredicateSupplier implements PredicateSupplier {
|
||||
|
||||
public static RequestPredicate alwaysTrue() {
|
||||
return request -> true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Method> get() {
|
||||
return List.of(TestPredicateSupplier.class.getMethods());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\
|
||||
org.springframework.cloud.gateway.server.mvc.test.TestPredicateSupplier
|
||||
|
||||
org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\
|
||||
org.springframework.cloud.gateway.server.mvc.test.TestFilterSupplier
|
||||
Reference in New Issue
Block a user