Spring-Cloud-Gateway路由信息是通过路由定位器RouteLocator加载以及初始化的接下来阅读源码看下Spring-Cloud-Gateway是怎么一步一步的实现了路由的加载初始化。
首选我们还是在Spring-Cloud-Gateway初始化配置中看Spring-Cloud-Gateway初始化是创建了路由定位相关的那些类
------------- GatewayAutoConfiguration类
/**
* 创建一个根据RouteDefinition转换的路由定位器
*/
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> GatewayFilters,
List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
}
/**
* 创建一个缓存路由的路由定位器
* @param routeLocators
* @return
*/
@Bean
@Primary//意思是在众多相同的bean中,优先使用用@Primary注解的bean.
//TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
//1.创建组合路由定位器,根据(容器)已有的路由定位器集合
//2.创建缓存功能的路由定位器
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
从初始化配置类中可以路由定位器的创建流程
- RouteDefinitionRouteLocator
- CompositeRouteLocator
- CachingRouteLocator
- 其中 RouteDefinitionRouteLocator 是获取路由的主要地方,CompositeRouteLocator,CachingRouteLocator对路由定位器做了附加功能的包装,最终使用的是CachingRouteLocator对外提供服务
下来阅读RouteLocator 接口源码:
/**
* 路由定位器,服务获取路由信息
* 1.可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route
* @author Spencer Gibb
*/
//TODO: rename to Routes?
public interface RouteLocator {
/**
* 获取路由
* @return
*/
Flux<Route> getRoutes();
}
接口很简单,有且只有一个获取路由的方法,专门用来获取路由。
RouteLocator 类图如下:
graph TD
RouteLocator-->|缓存功能实现|CachingRouteLocator
RouteLocator-->|组合功能实现|CompositeRouteLocator
RouteLocator-->|通过路由定义转换路由实现|RouteDefinitionRouteLocator
接下来我们依次阅读具体实现类
- CachingRouteLocator
/**
* 路由定位器的包装类,实现了路由的本地缓存功能
* @author Spencer Gibb
*/
public class CachingRouteLocator implements RouteLocator {
/**
* 目标路由定位器
*/
private final RouteLocator delegate;
/**
* 路由信息
* Flux 相当于一个 RxJava Observable,
* 能够发出 0~N 个数据项,然后(可选地)completing 或 erroring。处理多个数据项作为stream
*/
private final Flux<Route> routes;
/**
* 本地缓存,用于缓存路由定位器获取的路由集合
*
*/
private final Map<String, List> cache = new HashMap<>();
public CachingRouteLocator(RouteLocator delegate) {
this.delegate = delegate;
routes = CacheFlux.lookup(cache, "routes", Route.class)
.onCacheMissResume(() -> this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE));
}
@Override
public Flux<Route> getRoutes() {
return this.routes;
}
/**
* Clears the routes cache
* @return routes flux
*/
public Flux<Route> refresh() {
this.cache.clear();
return this.routes;
}
@EventListener(RefreshRoutesEvent.class)
/* for testing */ void handleRefresh() {
refresh();
}
}
- 此类实现了对路由信息的本地缓存,通过Map<String, List> cache 缓存路由到内存中
- 此类通过@EventListener(RefreshRoutesEvent.class)监听RefreshRoutesEvent事件实现了对缓存的动态刷新。
备注:动态刷新可以在GatewayControllerEndpoint中通过http请求发布刷新事件
@RestControllerEndpoint(id = "gateway")
public class GatewayControllerEndpoint implements ApplicationEventPublisherAware{
// 调用url= /gateway/refresh 刷新缓存中的路由信息
@PostMapping("/refresh")
public Mono<Void> refresh() {
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return Mono.empty();
}
}
- CompositeRouteLocator
/**
*
* 组合多个 RRouteLocator 的实现,为Route提供统一获取入口
* @author Spencer Gibb
*/
public class CompositeRouteLocator implements RouteLocator {
/**
* 能够发出 0~N 个数据项(RouteLocator),然后(可选地)completing 或 erroring。处理多个数据项作为stream
*/
private final Flux<RouteLocator> delegates;
public CompositeRouteLocator(Flux<RouteLocator> delegates) {
this.delegates = delegates;
}
@Override
public Flux<Route> getRoutes() {
//this.delegates.flatMap((routeLocator)-> routeLocator.getRoutes());
return this.delegates.flatMap(RouteLocator::getRoutes);
}
}
- 此类将遍历传入的目录路由定位器集合,组合每个路由定位器获取到的路由信息
- RouteDefinitionRouteLocator
/**
* 路由定位器
* 此实现通过路由定义(RouteDefinition)转换路由(Route)
* {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}
* @author Spencer Gibb
*/
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties) {
this.routeDefinitionLocator = routeDefinitionLocator;
initFactories(predicates);
gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
@Override
public Flux<Route> getRoutes() {
//获取到所有的RouteDefinition
return this.routeDefinitionLocator.getRouteDefinitions()
//遍历转换成对应的Route信息
.map(this::convertToRoute)
//TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
return route;
});
/* TODO: trace logging
if (logger.isTraceEnabled()) {
logger.trace("RouteDefinition did not match: " + routeDefinition.getId());
}*/
}
}
- 此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,
- 代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的
- RouteDefinitionRouteLocator:RouteDefinition转换
/**
* RouteDefinition 转换为对应的Route
* @param routeDefinition
* @return
*/
private Route convertToRoute(RouteDefinition routeDefinition) {
//获取routeDefinition中的Predicate信息
Predicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
//获取routeDefinition中的GatewayFilter信息
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
//构建路由信息
return Route.builder(routeDefinition)
.predicate(predicate)
.replaceFilters(gatewayFilters)
.build();
}
- convertToRoute方法功能作用
- 获取routeDefinition中的Predicate信息 (通过combinePredicates方法)
- 获取routeDefinition中的GatewayFilter信息(通过gatewayFilters方法)
- 构建路由信息
- RouteDefinitionRouteLocator:获取routeDefinition中的Predicate信息
/**
* 返回组合的谓词
* @param routeDefinition
* @return
*/
private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
//获取RouteDefinition中的PredicateDefinition集合
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));
for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
//流程4
//返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
predicate = predicate.and(found);
}
return predicate;
}
/**
* 获取一个谓语定义(PredicateDefinition)转换的谓语
* @param route
* @param predicate
* @return
*/
@SuppressWarnings("unchecked")
private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
//流程1
//流程1==获取谓语创建工厂
RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
if (factory == null) {
throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
}
//流程2
//获取参数
Map<String, String> args = predicate.getArgs();
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition " + route.getId() + " applying "
+ args + " to " + predicate.getName());
}
//组装参数
Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
//构建创建谓语的配置信息
Object config = factory.newConfig();
ConfigurationUtils.bind(config, properties,
factory.shortcutFieldPrefix(), predicate.getName(), validator);
if (this.publisher != null) {
this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));
}
//流程3
//通过谓语工厂构建谓语
return factory.apply(config);
}
PredicateDefinition 谓语定义以及在前面文中阅读过源码了
获取Predicate流程如下
- 根据PredicateDefinition name 获取 RoutePredicateFactory
- 根据PredicateDefinition args 组装 config信息
- 通过RoutePredicateFactory 根据config信息创建Predicate信息
- 多个Predicate 以短路逻辑AND组合
- RouteDefinitionRouteLocator:获取routeDefinition中的GatewayFilter信息
private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
List<GatewayFilter> filters = new ArrayList<>();
//校验gatewayProperties是否含义默认的过滤器集合
//TODO: support option to apply defaults after route specific filters?
if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
//加载全局配置的默认过滤器集合
filters.addAll(loadGatewayFilters("defaultFilters",
this.gatewayProperties.getDefaultFilters()));
}
if (!routeDefinition.getFilters().isEmpty()) {
//加载路由定义中的过滤器集合
filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
}
//排序
AnnotationAwareOrderComparator.sort(filters);
return filters;
}
/**
* 加载过滤器,根据过滤器的定义加载
* @param id
* @param filterDefinitions
* @return
*/
@SuppressWarnings("unchecked")
private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
//遍历过滤器定义,将过滤器定义转换成对应的过滤器
List<GatewayFilter> filters = filterDefinitions.stream()
.map(definition -> {
//流程1 //通过过滤器定义名称获取过滤器创建工厂
GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());
if (factory == null) {
throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
}
//流程2
//获取参数
Map<String, String> args = definition.getArgs();
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
}
//根据args组装配置信息
Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
//构建过滤器创建配置信息
Object configuration = factory.newConfig();
ConfigurationUtils.bind(configuration, properties,
factory.shortcutFieldPrefix(), definition.getName(), validator);
//流程3
//通过过滤器工厂创建GatewayFilter
GatewayFilter gatewayFilter = factory.apply(configuration);
if (this.publisher != null) {
//发布事件
this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
}
return gatewayFilter;
})
.collect(Collectors.toList());
ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
//包装过滤器使其所有过滤器继承Ordered属性,可进行排序
for (int i = 0; i < filters.size(); i++) {
GatewayFilter gatewayFilter = filters.get(i);
if (gatewayFilter instanceof Ordered) {
ordered.add(gatewayFilter);
}
else {
ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
}
}
return ordered;
}
- getFilters 方法 同时加载 全局配置 gatewayProperties与routeDefinition配置下的所有过滤器定义filterDefinitions
- loadGatewayFilters 负责将filterDefinition转化成对应的GatewayFilter
转化流程如下
- 根据filterDefinition name 获取 GatewayFilterFactory
- 根据filterDefinition args 组装 config信息
- 通过GatewayFilterFactory 根据config信息创建PGatewayFilter信息
至此,阅读了路由的数据模型,路由定义加载,路由的加载(路由定义转化为路由),Spring-Cloud-Gateway路由的创建加载流程已经清晰明了的展现出来,在使用中也可以快速的对其扩展,以及根据实际需求进行个性化的定制操作。
网友评论