Spring-Cloud-Gateway源码系列学习
版本 v2.2.6.RELEASE
demo搭建
Nacos下载地址:https://github.com/alibaba/nacos/releases/tag/2.0.0-BETA
解压进入bin目录
单机运行Nacos:
- windows系统:startup.cmd -m standalone
- linux/mac:startup.sh -m standalone
打开Nacos管理界面:
- 链接:http://localhost:8848/nacos
- 账号:nacos
- 密码:nacos
示例代码对应仓库():
示例代码由芋道源码提供,嘿嘿~
运行上面两个Spring-Boot程序
验证基于服务发现的动态路由:
http://localhost:8888/user-service/user/get?id=1
DiscoveryLocatorProperties源码分析
DiscoveryLocatorProperties是Spring-Cloud-Gateway discovery配置类,示例配置如下:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
url-expression: "'lb://' + serviceId"
下面通过 GatewayDiscoveryClientAutoConfiguration 类分析 ,DiscoveryLocatorProperties在装配时默认添加的predicate和filter
public class GatewayDiscoveryClientAutoConfiguration{
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
//设置了默认的predicate
properties.setPredicates(initPredicates());
//设置了默认的filter
properties.setFilters(initFilters());
return properties;
}
//默认predicate:-Path = "'/'+serviceId+'/**'"
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/**
//new一个PredicateDefinition
PredicateDefinition predicate = new PredicateDefinition();
//生产AsyncPredicate时是根据name来匹配PredicateFactory的
predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
//设置predicate配置,等于 -Path = "'/'+serviceId+'/**'"
predicate.addArg(PATTERN_KEY, "'/'+serviceId+'/**'");
definitions.add(predicate);
return definitions;
}
//默认filter:- RewritePath="'/' + serviceId + '/(?<remaining>.*)'", "'/${remaining}'"
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;
}
}
下面接着分析DiscoveryLocatorProperties的源码
public class DiscoveryLocatorProperties {
/** Flag that enables DiscoveryClient gateway integration. */
private boolean enabled = false;
/**
* The prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName()
* + "_". Service Id will be appended to create the routeId.
*/
//路由id前缀
private String routeIdPrefix;
/**
* SpEL expression that will evaluate whether to include a service in gateway
* integration or not, defaults to: true.
*/
//是否使用SpEL表达式
private String includeExpression = "true";
/**
* SpEL expression that create the uri for each route, defaults to: 'lb://'+serviceId.
*/
//创建路由使用的SpEL表达式
private String urlExpression = "'lb://'+serviceId";
/**
* Option to lower case serviceId in predicates and filters, defaults to false. Useful
* with eureka when it automatically uppercases serviceId. so MYSERIVCE, would match
* /myservice/**
*/
//是否开启大写转小写
private boolean lowerCaseServiceId = false;
//作用于每个服务发现路由的Predicate
private List<PredicateDefinition> predicates = new ArrayList<>();
//作用于每个服务发现路由的Filter
private List<FilterDefinition> filters = new ArrayList<>();
}
DiscoveryClientRouteDefinitionLocator源码分析
通过DiscoveryClient提供的Flux<List> serviceInstances 和 DiscoveryLocatorProperties properties来创建RouteDefinition
//TODO