Spring Cloud Gateway源码解析-02-初始化解析之Route、Predicate、Filter的装配原理

1,246 阅读5分钟

上篇文章中我们看到,通过配置如下配置即可对请求进行路由匹配过滤及转发,并且得知SCG内置了多种Filter和Predicate,通过类似- Path=/login或者- StripPrefix=1这种就可以匹配到SCG内置的PathRoutePredicateFactoryStripPrefixGatewayFilterFactory,那么SCG是怎么对我们的配置进行封装和匹配的呢?

spring:
  cloud:
		#SCG的配置,对应GatewayProperties
    gateway:
      routes:
      - id: user-service #路由的编号(唯一)
        uri: http://127.0.0.1:8080 #路由到的目标地址
        predicates: # 断言,作为路由的匹配条件 对应RouteDefinition,可以配置多个
        	- Path=/login,/loginUser
				filters:
					- StripPrefix=1 #下边说

自动装配

SCG是基于Springboot的,Springboot通过读取spring.factories文件进行自动装配所需的Bean,spring-cloud-gateway-server工程中的spring.factories文件中配置了SCG需要自动装配的类。

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayHystrixCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration,\
org.springframework.cloud.gateway.config.SimpleUrlHandlerMappingGlobalCorsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

本文只需要重点关注**GatewayAutoConfiguration****,SCG的核心配置类。**
GatewayAutoConfiguration的注解上可以看到@ConditionalOnProperty``(name = ``"spring.cloud.gateway.enabled"``, ``matchIfMissing = ``true``),通过spring.cloud.gateway.enabled来配置SCG的开启与关闭,并且默认为开启

GatewayAutoConfiguration中初始化的主要组件

  • GatewayProperties:在上篇文章中已经阐明了此类的作用,用来读取封装配置文件中配置的RouteDefinitionFilterDefinitionPredicationDefinition,即路由信息
  • RouteDefinitionLocator:存储从配置文件中读取的路由信息
  • RouteLocator:API驱动所需的Bean
  • FilteringWebHandler:后边的文章会做解析
  • RoutePredicateHandlerMapping:后边的文章会做解析
  • FilterFactory:创建org.springframework.cloud.gateway.filter.factory包下所有的实现了GatewayFilterFactory的类
  • PredicateFactory:创建org.springframework.cloud.gateway.handler.predicate包下所有实现了RoutePredicateFactory接口的类

GatewayProperties

	/**
	 *  读取配置文件中配置的的{@link RouteDefinition} 
   			->>{@link FilterDefinition} ->> {@link PredicateDefinition}并封装
	 * @return
	 */
	@Bean
	public GatewayProperties gatewayProperties() {
		return new GatewayProperties();
	}
public class GatewayProperties {

	/**
	 * Properties prefix.
	 */
	public static final String PREFIX = "spring.cloud.gateway";
	/**
	 * List of Routes.
	 */
	@NotNull
	@Valid
	private List<RouteDefinition> routes = new ArrayList<>();

	/**
	 * 作用于每个路由的过滤器列表
	 */
	private List<FilterDefinition> defaultFilters = new ArrayList<>();
					..........省略部分代码............
}

RouteDefinition路由信息

public class RouteDefinition {
	
  //路由ID,如果配置为空则SCG会生成随机生成一个
	private String id;
	
	@NotEmpty
	@Valid
  //配置的断言信息
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
  //配置的过滤器信息
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
  //需要转发到的目的URI
	private URI uri;
}

PredicateDefinition断言信息

public class PredicateDefinition {

	@NotNull
	/**
	 * 断言的名称,与{@link AbstractRoutePredicateFactory}的子类名称前缀相同
	 */
	private String name;

	/**
	 * 断言的参数  key:_genkey_0 value:/login
	 */
	private Map<String, String> args = new LinkedHashMap<>();

	public PredicateDefinition() {
	}

	public PredicateDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			throw new ValidationException("Unable to parse PredicateDefinition text '"
					+ text + "'" + ", must be of the form name=value");
		}
		setName(text.substring(0, eqIdx));
		//将配置的字符串参数中"="右边的字符串以","分割
		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
		//遍历","分割后的结果,随机生成一个key(_genkey_+参数下标),value为参数
		for (int i = 0; i < args.length; i++) {
			this.args.put(NameUtils.generateName(i), args[i]);
		}
	}
}

在这里插入图片描述

FilterDefinition过滤器信息

与PredicateDefinition类似。
至此已经将配置中的信息封装到了对应的Definition中了

RouteDefinitionLocator

public interface RouteDefinitionLocator {
  
	//获取所有的路由信息
	Flux<RouteDefinition> getRouteDefinitions();

}

主要实现类:PropertiesRouteDefinitionLocatorCompositeRouteDefinitionLocator

/**
	 * PropertiesRouteDefinitionLocator 是{@link RouteDefinitionLocator}的实现类 用于存储从配置文件中读取的路由信息
	 * @param properties 即为上边装配的GatewayProperties Bean
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
			GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}
/**
	 * 将上边装配的RouteDefinitionLocator再次进行组装
	 * @param routeDefinitionLocators
	 * @return
	 */
	@Bean
	@Primary //定义为Primary是为了下边装配RouteDefinitionRouteLocator时此Bean为注入的RouteDefinitionLocator Bean
	public RouteDefinitionLocator routeDefinitionLocator(
			List<RouteDefinitionLocator> routeDefinitionLocators) {
		return new CompositeRouteDefinitionLocator(
				Flux.fromIterable(routeDefinitionLocators));
	}


此类会判断路由id是否为空,如果为空则生成一个

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return this.delegates
				.flatMapSequential(RouteDefinitionLocator::getRouteDefinitions)
				.flatMap(routeDefinition -> {
					if (routeDefinition.getId() == null) {
						//如果路由id为空,则生成一个
						return randomId().map(id -> {
							routeDefinition.setId(id);
							if (log.isDebugEnabled()) {
								log.debug(
										"Id set on route definition: " + routeDefinition);
							}
							return routeDefinition;
						});
					}
					return Mono.just(routeDefinition);
				});
	}

	protected Mono<String> randomId() {
		return Mono.fromSupplier(idGenerator::toString)
				.publishOn(Schedulers.boundedElastic());
	}

}

GatewayFilter Factory beans

**装配org.springframework.cloud.gateway.handler.predicate包下RoutePredicateFactory**实现类

@Bean
	@ConditionalOnEnabledFilter
	public AddRequestHeaderGatewayFilterFactory addRequestHeaderGatewayFilterFactory() {
		return new AddRequestHeaderGatewayFilterFactory();
	}

	@Bean
	@ConditionalOnEnabledFilter
	public MapRequestHeaderGatewayFilterFactory mapRequestHeaderGatewayFilterFactory() {
		return new MapRequestHeaderGatewayFilterFactory();
	}
....等等...

Predicate Factory beans

装配**org.springframework.cloud.gateway.filter.factory**包下GatewayFilterFactory实现类

@Bean
	@ConditionalOnEnabledPredicate
	public AfterRoutePredicateFactory afterRoutePredicateFactory() {
		return new AfterRoutePredicateFactory();
	}

	@Bean
	@ConditionalOnEnabledPredicate
	public BeforeRoutePredicateFactory beforeRoutePredicateFactory() {
		return new BeforeRoutePredicateFactory();
	}
....等等...

RouteLocator

public interface RouteLocator {
	//用来获取路由的
	Flux<Route> getRoutes();

}

在这里插入图片描述
RouteDefinitionRouteLocator为本节重点,其他两个实现后边会讲解

	/**
	 *
	 * @param properties 即为装配的GatewayProperties Bean
	 * @param gatewayFilters 即为装配的 GatewayFilterFactory所有的实现类
	 * @param predicates 即为装配的  RoutePredicateFactory 所有的实现类
	 * @param routeDefinitionLocator 即为装配的RouteDefinitionLocator ->CompositeRouteDefinitionLocator
	 * @return
	 */
	@Bean
	public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
			List<GatewayFilterFactory> gatewayFilters,
			List<RoutePredicateFactory> predicates,
			RouteDefinitionLocator routeDefinitionLocator,
			ConfigurationService configurationService) {
		return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
				gatewayFilters, properties, configurationService);
	}

/**
	 * CachingRouteLocator为RoutePredicateHandlerMapping的RouteLocator,见 {@link this#routePredicateHandlerMapping}
	 * @param routeLocators 上边装配的RouteDefinitionRouteLocator的Bean
	 * @return
	 */
	@Bean
	@Primary //定义为Primary为下边装配RoutePredicateHandlerMapping时使用
	@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
	public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
		return new CachingRouteLocator(
				new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
	}

RouteDefinitionRouteLocator

此类主要是组装了RouteDefinitionLocator RoutePredicateFactoryGatewayFilterFactory,从而通过这些信息转换成Route

public class RouteDefinitionRouteLocator
		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {

	/**
	 * Default filters name.
	 */
	public static final String DEFAULT_FILTERS = "defaultFilters";

	protected final Log logger = LogFactory.getLog(getClass());

	private final RouteDefinitionLocator routeDefinitionLocator;

	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();

	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

	private final GatewayProperties gatewayProperties;

	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
			List<RoutePredicateFactory> predicates,
			List<GatewayFilterFactory> gatewayFilterFactories,
			GatewayProperties gatewayProperties,
			ConfigurationService configurationService) {
		this.routeDefinitionLocator = routeDefinitionLocator;
		this.configurationService = configurationService;
		//初始化Predicate断言信息(所有的)
		initFactories(predicates);
		//初始化Filter信息(所有的),与初始化Predicate断言信息类似
		gatewayFilterFactories.forEach(
				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
		this.gatewayProperties = gatewayProperties;
	}

	private void initFactories(List<RoutePredicateFactory> predicates) {
		predicates.forEach(factory -> {
			//key为RoutePredicateFactory实现类的名称前缀如AfterRoutePredicateFactory则key为After
			String key = factory.name();
			if (this.predicates.containsKey(key)) {
				this.logger.warn("A RoutePredicateFactory named " + key
						+ " already exists, class: " + this.predicates.get(key)
						+ ". It will be overwritten.");
			}
			//如果已经存在该断言Factory,则覆盖,也就是说以SCG内置的为主
			this.predicates.put(key, factory);
			if (logger.isInfoEnabled()) {
				logger.info("Loaded RoutePredicateFactory [" + key + "]");
			}
		});
	}

getRoutes()

此方法为CachingRouteLocator调用,返回路由信息。

CachingRouteLocator后边的文章会讲解

	@Override
	public Flux<Route> getRoutes() {
		//通过RouteDefinitions获取Route
		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
				.map(this::convertToRoute);

		if (!gatewayProperties.isFailOnRouteDefinitionError()) {
			// instead of letting error bubble up, continue
			routes = routes.onErrorContinue((error, obj) -> {
				if (logger.isWarnEnabled()) {
					logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
							+ " will be ignored. Definition has invalid configs, "
							+ error.getMessage());
				}
			});
		}
		
		return routes.map(route -> {
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition matched: " + route.getId());
			}
			return route;
		});
	}

convertToRoute将RouteDefinition转换为Route

/**
	 * 将RouteDefinition转换为Route
	 * @param routeDefinition
	 * @return
	 */
	private Route convertToRoute(RouteDefinition routeDefinition) {
		/**
		 * 重点
		 * 获取RouteDefinition对应的断言
		 */
		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
		/**
		 * 重点
		 * 获取RouteDefinition对应的Filter
		 */
		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);

		return Route.async(routeDefinition).asyncPredicate(predicate)
				.replaceFilters(gatewayFilters).build();
	}

combinePredicates

PredicateDefinition合并为一个AsyncPredicate

private AsyncPredicate<ServerWebExchange> combinePredicates(
			RouteDefinition routeDefinition) {
		List<PredicateDefinition> predicates = routeDefinition.getPredicates();
		if (predicates == null || predicates.isEmpty()) {
			// this is a very rare case, but possible, just match all
			return AsyncPredicate.from(exchange -> true);
		}
		AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
				predicates.get(0));
		//此处是为了如果此RouteDefinition配置了多个Predicate,将多个AsyncPredicate通过与(and)连接起来
		for (PredicateDefinition andPredicate : predicates.subList(1,
				predicates.size())) {
			AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
					andPredicate);
			predicate = predicate.and(found);
		}

		return predicate;
	}

private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
			PredicateDefinition predicate) {
		//查找到PredicateDefinition对应的RoutePredicateFactory
		RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
		if (factory == null) {
			throw new IllegalArgumentException(
					"Unable to find RoutePredicateFactory with name "
							+ predicate.getName());
		}
		if (logger.isDebugEnabled()) {
			logger.debug("RouteDefinition " + route.getId() + " applying "
					+ predicate.getArgs() + " to " + predicate.getName());
		}
		//每个RoutePredicateFactory实现中都有Config,可以理解为我们配置的参数规则,生成此Config
		// @formatter:off
		Object config = this.configurationService.with(factory)
				.name(predicate.getName())
				.properties(predicate.getArgs())
				.eventFunction((bound, properties) -> new PredicateArgsEvent(
						RouteDefinitionRouteLocator.this, route.getId(), properties))
				.bind();
		// @formatter:on
		//生成异步断言
		return factory.applyAsync(config);
	}

getFilters

获取所有的过滤器,排序后的

private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
		List<GatewayFilter> filters = new ArrayList<>();
		//添加默认过滤器
		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
					new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
		}
		//添加配置的过滤器
		if (!routeDefinition.getFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
					new ArrayList<>(routeDefinition.getFilters())));
		}
		//排序
		AnnotationAwareOrderComparator.sort(filters);
		return filters;
	}

List<GatewayFilter> loadGatewayFilters(String id,
			List<FilterDefinition> filterDefinitions) {
		ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
		for (int i = 0; i < filterDefinitions.size(); i++) {
			FilterDefinition definition = filterDefinitions.get(i);
			//获取FilterDefinition对应的GatewayFilterFactory
			GatewayFilterFactory factory = this.gatewayFilterFactories
					.get(definition.getName());
			if (factory == null) {
				throw new IllegalArgumentException(
						"Unable to find GatewayFilterFactory with name "
								+ definition.getName());
			}
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition " + id + " applying filter "
						+ definition.getArgs() + " to " + definition.getName());
			}
			//生成配置类,与Predicate类似
			// @formatter:off
			Object configuration = this.configurationService.with(factory)
					.name(definition.getName())
					.properties(definition.getArgs())
					.eventFunction((bound, properties) -> new FilterArgsEvent(
							// TODO: why explicit cast needed or java compile fails
							RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
					.bind();
			// @formatter:on

			// some filters require routeId
			// TODO: is there a better place to apply this?
			if (configuration instanceof HasRouteId) {
				HasRouteId hasRouteId = (HasRouteId) configuration;
				hasRouteId.setRouteId(id);
			}
			//生成GatewayFilter
			GatewayFilter gatewayFilter = factory.apply(configuration);
			if (gatewayFilter instanceof Ordered) {
				ordered.add(gatewayFilter);
			}
			else {
				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
			}
		}

		return ordered;
	}

总结

至此,主角Route终于现身了。了解清楚了SCG是如何通过配置生成路由及路由的断言和过滤器,接下来分析请求的接入及转发过程。