推荐阅读:[spring6: Mvc-函数式编程]-源码解析
GatewayServerMvcAutoConfiguration
@AutoConfiguration(after = {
HttpClientAutoConfiguration.class,
RestTemplateAutoConfiguration.class,
RestClientAutoConfiguration.class,
FilterAutoConfiguration.class,
HandlerFunctionAutoConfiguration.class,
PredicateAutoConfiguration.class
})
@ConditionalOnProperty(name = GatewayMvcProperties.PREFIX + ".enabled", matchIfMissing = true)
@Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class)
public class GatewayServerMvcAutoConfiguration {
// ...
@Bean
public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env, BeanFactory beanFactory,
FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer,
PredicateBeanFactoryDiscoverer predicateBeanFactoryDiscoverer) {
return new RouterFunctionHolderFactory(env, beanFactory, filterBeanFactoryDiscoverer,
predicateBeanFactoryDiscoverer);
}
}
GatewayMvcPropertiesBeanDefinitionRegistrar
/**
* BeanDefinitionRegistrar that registers a RouterFunctionHolder and a
* DelegatingRouterFunction.
*
* @author Spencer Gibb
* @author Pavel Tregl
* @author Jürgen Wißkirchen
*/
public class GatewayMvcPropertiesBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// registers a RouterFunctionHolder that specifically isn't a RouterFunction since
// RouterFunctionMapping gets a list of RouterFunction and if you put
// RouterFunction in refresh scope, RouterFunctionMapping will end up with two.
// Registers RouterFunctionHolderFactory::routerFunctionHolderSupplier so when the
// bean is refreshed, that method is called again.
AbstractBeanDefinition routerFnProviderBeanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(RouterFunctionHolder.class)
.setFactoryMethodOnBean("routerFunctionHolderSupplier", "routerFunctionHolderFactory")
.getBeanDefinition();
BeanDefinitionHolder holder = new BeanDefinitionHolder(routerFnProviderBeanDefinition,
"gatewayRouterFunctionHolder");
BeanDefinitionHolder proxy = ScopedProxyUtils.createScopedProxy(holder, registry, true);
// Puts the RouterFunctionHolder in refresh scope, if not disabled.
if (registry.containsBeanDefinition("refreshScope")) {
routerFnProviderBeanDefinition.setScope("refresh");
}
if (registry.containsBeanDefinition(proxy.getBeanName())) {
registry.removeBeanDefinition(proxy.getBeanName());
}
registry.registerBeanDefinition(proxy.getBeanName(), proxy.getBeanDefinition());
// registers a DelegatingRouterFunction(RouterFunctionHolder) bean this way the
// holder can be refreshed and all config based routes will be reloaded.
AbstractBeanDefinition routerFunctionBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(DelegatingRouterFunction.class)
.getBeanDefinition();
registry.registerBeanDefinition("gatewayCompositeRouterFunction", routerFunctionBeanDefinition);
}
/**
* Simply holds the composite gateway RouterFunction. This class can be refresh scope
* without fear of having multiple RouterFunction mappings.
*/
public static class RouterFunctionHolder {
private final RouterFunction<ServerResponse> routerFunction;
public RouterFunctionHolder(RouterFunction<ServerResponse> routerFunction) {
this.routerFunction = routerFunction;
}
public RouterFunction<ServerResponse> getRouterFunction() {
return this.routerFunction;
}
}
/**
* Delegating RouterFunction impl that delegates to the refreshable
* RouterFunctionHolder.
*/
static class DelegatingRouterFunction implements RouterFunction<ServerResponse> {
final RouterFunctionHolder provider;
DelegatingRouterFunction(RouterFunctionHolder provider) {
this.provider = provider;
}
@Override
public RouterFunction<ServerResponse> and(RouterFunction<ServerResponse> other) {
return this.provider.getRouterFunction().and(other);
}
@Override
public RouterFunction<?> andOther(RouterFunction<?> other) {
return this.provider.getRouterFunction().andOther(other);
}
@Override
public RouterFunction<ServerResponse> andRoute(RequestPredicate predicate,
HandlerFunction<ServerResponse> handlerFunction) {
return this.provider.getRouterFunction().andRoute(predicate, handlerFunction);
}
@Override
public RouterFunction<ServerResponse> andNest(RequestPredicate predicate,
RouterFunction<ServerResponse> routerFunction) {
return this.provider.getRouterFunction().andNest(predicate, routerFunction);
}
@Override
public <S extends ServerResponse> RouterFunction<S> filter(
HandlerFilterFunction<ServerResponse, S> filterFunction) {
return this.provider.getRouterFunction().filter(filterFunction);
}
@Override
public void accept(RouterFunctions.Visitor visitor) {
this.provider.getRouterFunction().accept(visitor);
}
@Override
public RouterFunction<ServerResponse> withAttribute(String name, Object value) {
return this.provider.getRouterFunction().withAttribute(name, value);
}
@Override
public RouterFunction<ServerResponse> withAttributes(Consumer<Map<String, Object>> attributesConsumer) {
return this.provider.getRouterFunction().withAttributes(attributesConsumer);
}
@Override
public Optional<HandlerFunction<ServerResponse>> route(ServerRequest request) {
return this.provider.getRouterFunction().route(request);
}
@Override
public String toString() {
return this.provider.getRouterFunction().toString();
}
}
}
RouterFunctionHolderFactory
/**
* Factory bean for the creation of a RouterFunctionHolder, that may have refresh scope.
*
* @author Spencer Gibb
* @author Jürgen Wißkirchen
*/
public class RouterFunctionHolderFactory {
private static final RequestPredicate neverPredicate = new RequestPredicate() {
@Override
public boolean test(ServerRequest request) {
return false;
}
@Override
public String toString() {
return "Never";
}
};
private static final RouterFunction<ServerResponse> NEVER_ROUTE = RouterFunctions.route(neverPredicate,
request -> ServerResponse.notFound().build());
private final Log log = LogFactory.getLog(getClass());
private final TrueNullOperationArgumentResolver trueNullOperationArgumentResolver = new TrueNullOperationArgumentResolver();
private final Environment env;
// 基于 SPI 机制的过滤器发现器,负责从所有 FilterSupplier 加载并收集返回类型为 HandlerFilterFunction 的过滤器方法。
private final FilterDiscoverer filterDiscoverer = new FilterDiscoverer();
// 基于 SPI 的处理器发现器,负责从所有 HandlerSupplier 加载返回类型为 HandlerFunction 或 HandlerDiscoverer.Result 的处理方法
private final HandlerDiscoverer handlerDiscoverer = new HandlerDiscoverer();
// 基于 SPI 的谓词发现器,负责从所有 PredicateSupplier 加载返回类型为 RequestPredicate 的路由条件方法
private final PredicateDiscoverer predicateDiscoverer = new PredicateDiscoverer();
private final ParameterValueMapper parameterValueMapper = new ConversionServiceParameterValueMapper();
private final BeanFactory beanFactory;
// 基于 Spring BeanFactory 的过滤器发现器,用于按顺序加载所有 FilterSupplier,发现返回类型为 HandlerFilterFunction 的过滤器方法
private final FilterBeanFactoryDiscoverer filterBeanFactoryDiscoverer;
// 基于 Spring BeanFactory 的谓词发现器,用于按顺序加载所有 PredicateSupplier,实现对返回类型为 RequestPredicate 的路由条件方法的发现
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();
}
}
/**
* supplier for RouterFunctionHolder, which is registered as factory method on the
* bean definition.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder routerFunctionHolderSupplier() {
GatewayMvcProperties properties = Binder.get(env)
.bindOrCreate(GatewayMvcProperties.PREFIX, GatewayMvcProperties.class);
log.trace(LogMessage.format("RouterFunctionHolder initializing with %d map routes and %d list routes",
properties.getRoutesMap().size(), properties.getRoutes().size()));
Map<String, RouterFunction> routerFunctions = new LinkedHashMap<>();
properties.getRoutes().forEach(routeProperties -> {
routerFunctions.put(routeProperties.getId(), getRouterFunction(routeProperties, routeProperties.getId()));
});
properties.getRoutesMap().forEach((routeId, routeProperties) -> {
String computedRouteId = routeId;
if (StringUtils.hasText(routeProperties.getId())) {
computedRouteId = routeProperties.getId();
}
routerFunctions.put(computedRouteId, getRouterFunction(routeProperties, computedRouteId));
});
RouterFunction routerFunction;
if (routerFunctions.isEmpty()) {
// no properties routes, so a RouterFunction that will never match
routerFunction = NEVER_ROUTE;
}
else {
routerFunction = routerFunctions.values().stream().reduce(RouterFunction::andOther).orElse(null);
// puts the map of configured RouterFunctions in an attribute. Makes testing
// easy.
routerFunction = routerFunction.withAttribute("gatewayRouterFunctions", routerFunctions);
}
log.trace(LogMessage.format("RouterFunctionHolder initialized %s", routerFunction.toString()));
return new GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder(routerFunction);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private RouterFunction getRouterFunction(RouteProperties routeProperties, String routeId) {
log.trace(LogMessage.format("Creating route for : %s", routeProperties));
RouterFunctions.Builder builder = route(routeId);
MultiValueMap<String, OperationMethod> handlerOperations = handlerDiscoverer.getOperations();
// TODO: cache?
// translate handlerFunction
String scheme = routeProperties.getUri().getScheme();
// 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 (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) {
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 = new LinkedMultiValueMap<>();
if (predicateBeanFactoryDiscoverer != null) {
predicateOperations.addAll(predicateBeanFactoryDiscoverer.getOperations());
}
predicateOperations.addAll(predicateDiscoverer.getOperations());
final AtomicReference<RequestPredicate> predicate = new AtomicReference<>();
routeProperties.getPredicates().forEach(predicateProperties -> {
Map<String, Object> args = new LinkedHashMap<>(predicateProperties.getArgs());
translate(predicateOperations, predicateProperties.getName(), args, RequestPredicate.class,
requestPredicate -> {
log.trace(LogMessage.format("Adding predicate to route %s - %s", routeId, predicateProperties));
if (predicate.get() == null) {
predicate.set(requestPredicate);
}
else {
RequestPredicate combined = predicate.get().and(requestPredicate);
predicate.set(combined);
}
log.trace(LogMessage.format("Combined predicate for route %s - %s", routeId, predicate.get()));
});
});
// combine predicate and handlerFunction
builder.route(predicate.get(), handlerFunction);
predicate.set(null);
// HandlerDiscoverer filters needing lower priority, so put them first
lowerPrecedenceFilters.forEach(builder::filter);
// translate filters
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);
});
// HandlerDiscoverer filters need higher priority, so put them last
higherPrecedenceFilters.forEach(builder::filter);
builder.withAttribute(MvcUtils.GATEWAY_ROUTE_ID_ATTR, routeId);
return builder.build();
}
private <T> void translate(MultiValueMap<String, OperationMethod> operations, String operationName,
Map<String, Object> operationArgs, Class<T> returnType, Consumer<T> operationHandler) {
String normalizedName = StringUtils.uncapitalize(operationName);
Optional<NormalizedOperationMethod> operationMethod = findOperation(operations, normalizedName, operationArgs);
if (operationMethod.isPresent()) {
NormalizedOperationMethod opMethod = operationMethod.get();
T handlerFilterFunction = invokeOperation(opMethod, opMethod.getNormalizedArgs());
if (handlerFilterFunction != null) {
operationHandler.accept(handlerFilterFunction);
}
if (log.isDebugEnabled()) {
log.debug(LogMessage.format("Yaml Properties matched Operations name: %s, args: %s, params: %s",
normalizedName, opMethod.getNormalizedArgs().toString(),
Arrays.toString(opMethod.getParameters().stream().toArray())));
}
}
else {
throw new IllegalArgumentException(String.format("Unable to find operation %s for %s with args %s",
returnType, normalizedName, operationArgs));
}
}
private Optional<NormalizedOperationMethod> findOperation(MultiValueMap<String, OperationMethod> operations,
String operationName, Map<String, Object> operationArgs) {
return operations.getOrDefault(operationName, Collections.emptyList())
.stream()
.sorted(Comparator.comparing(OperationMethod::isConfigurable))
.map(operationMethod -> new NormalizedOperationMethod(operationMethod, operationArgs))
.filter(opeMethod -> matchOperation(opeMethod, operationArgs))
.findFirst();
}
private static boolean matchOperation(NormalizedOperationMethod operationMethod, Map<String, Object> args) {
Map<String, Object> normalizedArgs = operationMethod.getNormalizedArgs();
OperationParameters parameters = operationMethod.getParameters();
if (operationMethod.isConfigurable()) {
// this is a special case
return true;
}
if (parameters.getParameterCount() != normalizedArgs.size()) {
return false;
}
for (int i = 0; i < parameters.getParameterCount(); i++) {
if (!normalizedArgs.containsKey(parameters.get(i).getName())) {
return false;
}
}
// args contains all parameter names
return true;
}
private <T> T invokeOperation(OperationMethod operationMethod, Map<String, Object> operationArgs) {
Map<String, Object> args = new HashMap<>();
if (operationMethod.isConfigurable()) {
OperationParameter operationParameter = operationMethod.getParameters().get(0);
Object config = bindConfigurable(operationMethod, operationArgs, operationParameter);
args.put(operationParameter.getName(), config);
}
else {
args.putAll(operationArgs);
}
ReflectiveOperationInvoker operationInvoker = new ReflectiveOperationInvoker(operationMethod,
this.parameterValueMapper);
InvocationContext context = new InvocationContext(args, trueNullOperationArgumentResolver);
return operationInvoker.invoke(context);
}
private Object bindConfigurable(OperationMethod operationMethod, Map<String, Object> args,
OperationParameter operationParameter) {
Class<?> configurableType = operationParameter.getType();
Configurable configurable = operationMethod.getMethod().getAnnotation(Configurable.class);
if (configurable != null && !configurable.value().equals(Void.class)) {
configurableType = configurable.value();
}
Bindable<?> bindable = Bindable.of(configurableType);
List<ConfigurationPropertySource> propertySources = Collections
.singletonList(new MapConfigurationPropertySource(args));
Binder binder = new Binder(propertySources, null, conversionService);
Object config = binder.bindOrCreate("", bindable, new IgnoreTopLevelConverterNotFoundBindHandler());
return config;
}
static class TrueNullOperationArgumentResolver implements OperationArgumentResolver {
@Override
public boolean canResolve(Class<?> type) {
return true;
}
@Override
public <T> T resolve(Class<T> type) {
return null;
}
}
}