[spring6: Mvc-网关]-源码解析

发布于:2025-07-28 ⋅ 阅读:(19) ⋅ 点赞:(0)

推荐阅读:[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;
		}

	}
}

网站公告

今日签到

点亮在社区的每一天
去签到