在上篇文章中我们看到,通过配置如下配置即可对请求进行路由匹配过滤及转发,并且得知SCG内置了多种Filter和Predicate,通过类似- Path=/login
或者- StripPrefix=1
这种就可以匹配到SCG内置的PathRoutePredicateFactory
和StripPrefixGatewayFilterFactory
,那么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
:在上篇文章中已经阐明了此类的作用,用来读取封装配置文件中配置的RouteDefinition
、FilterDefinition
、PredicationDefinition
,即路由信息RouteDefinitionLocator
:存储从配置文件中读取的路由信息RouteLocator
:API驱动所需的BeanFilteringWebHandler
:后边的文章会做解析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();
}
主要实现类:PropertiesRouteDefinitionLocator
、CompositeRouteDefinitionLocator
/**
* 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
、RoutePredicateFactory
、GatewayFilterFactory
,从而通过这些信息转换成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是如何通过配置生成路由及路由的断言和过滤器,接下来分析请求的接入及转发过程。