我们开始查看gateway-server种的spring.factories时,除了主要的GatewayAutoConfiguration时,还有很多其他的自动配置类,这次只看 GatewayDiscoveryClientAutoConfiguration它是做什么的,我最开始是以为它是做动态路由,结果在后续查看启动日志以及其他代码后又翻回来看发现不是。
1、自动注册服务路由
通过查询官网文档,发现下面的解释
12.4. The DiscoveryClient Route Definition Locator
You can configure the gateway to create routes based on services registered with a
DiscoveryClientcompatible service registry.To enable this, set
spring.cloud.gateway.discovery.locator.enabled=trueand make sure aDiscoveryClientimplementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.
可以看到这里的配置正好和GatewayDiscoveryClientAutoConfiguration中的配置对应
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.discovery.reactive.enabled", matchIfMissing = true)
public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
}在往下翻官网文档就大概明白是什么意思了。我们在我们的demo 配置文件中把开关spring.cloud.gateway.discovery.locator.enabled打开。然后访问gateway的路由列表发现我们的路由列表里多了一个之前不存在的路由

而这个test正是我为了测试路由转发的一个测试项目,并且它也是和gateway处于同一个注册中心的 。结合官网解释并本地测试就可以验证,GatewayDiscoveryClientAutoConfiguration的作用就是将中心中心的项目自动注册成路由,Predicate和filter是默认的生成规则
public static List<PredicateDefinition> initPredicates() {
ArrayList<PredicateDefinition> definitions = new ArrayList<>();
// TODO: add a predicate that matches the url at /serviceId?
// add a predicate that matches the url at /serviceId/**
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
predicate.addArg(PATTERN_KEY, "'/'+serviceId+'/**'");
definitions.add(predicate);
return definitions;
}
public static List<FilterDefinition> initFilters() {
ArrayList<FilterDefinition> definitions = new ArrayList<>();
// add a filter that removes /serviceId by default
FilterDefinition filter = new FilterDefinition();
filter.setName(normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
String regex = "'/' + serviceId + '/?(?<remaining>.*)'";
String replacement = "'/${remaining}'";
filter.addArg(REGEXP_KEY, regex);
filter.addArg(REPLACEMENT_KEY, replacement);
definitions.add(filter);
return definitions;
}
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}其实它就是转换成
predicates:
- Path=/{serviceId}/**当然,如果我们想用自动注册路由又想定制其他谓词和过滤器,也是支持的
spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name: CircuitBreaker
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
2、服务从何而来
从上面的代码我们可以看到,除了new一个默认的properties bean外,其实没有看到服务是怎么注册到gateway来的。我们在自动配置文件中看到new了一个DiscoveryClientRouteDefinitionLocator,根据gateway里的命名规律,我们知道它就是服务发现客户端路由转换类,我们debug看下new的参数

这里服务发现客户端就是nacos的,也就是在nacos加载完成后,才会进行加载这个DiscoveryClientRouteDefinitionLocator bean,此时nacos已经知道了已经有哪些服务注册在它本身了。所以在DiscoveryClientRouteDefinitionLocator构造方法中其实已经将服务列表设置进了它的属性serviceInstances里。
我们看到DiscoveryClientRouteDefinitionLocator它本身也属于RouteDefinitionLocator,根据前面说的gateway的加载规则,在初始化RouteDefinitionRouteLocator时,会调用到DiscoveryClientRouteDefinitionLocator的getRouteDefinitions方法,在这里就进行了注册中心服务列表和配置文件规则组织成 路由定义。
