关注 微信公众号:【芋道源码】 有福利:
本文主要对 RouteDefinitionRepository 的源码实现 。
 
 
本文涉及到的类图如下 :
 
 
 org.springframework.cloud.gateway.route.RouteDefinitionWriter ,路由配置写入 接口 。该接口定义了 保存 与 删除 两个方法,代码如下 : 
public interface RouteDefinitionWriter{
 /**
* 保存路由配置
*
* @param route 路由配置
* @return Mono<Void>
*/
 Mono<Void> save(Mono<RouteDefinition> route);
 /**
* 删除路由配置
*
* @param routeId 路由编号
* @return Mono<Void>
*/
 Mono<Void> delete(Mono<String> routeId);
}
 
   org.springframework.cloud.gateway.route.RouteDefinitionRepository ,存储器 RouteDefinitionLocator 接口 ,代码如下 : 
public interface RouteDefinitionRepository extends RouteDefinitionLocator, RouteDefinitionWriter{
}
 
  通过实现该接口,实现从 存储器 ( 例如,内存 / Redis / MySQL 等 )读取、保存、删除路由配置。
目前 Spring Cloud Gateway 实现了 基于内存为存储器 的 InMemoryRouteDefinitionRepository 。
 org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository , 基于内存为存储器 的 RouteDefinitionLocator ,代码如下 : 
public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository{
 /**
* 路由配置映射
* key :路由编号 {@link RouteDefinition#id}
*/
 private final Map<String, RouteDefinition> routes = synchronizedMap(new LinkedHashMap<String, RouteDefinition>());
 @Override
 public Mono<Void> save(Mono<RouteDefinition> route){
 return route.flatMap( r -> {
 routes.put(r.getId(), r);
 return Mono.empty();
 });
 }
 @Override
 public Mono<Void> delete(Mono<String> routeId){
 return routeId.flatMap(id -> {
 if (routes.containsKey(id)) {
 routes.remove(id);
 return Mono.empty();
 }
 return Mono.error(new NotFoundException("RouteDefinition not found: "+routeId));
 });
 }
 @Override
 public Flux<RouteDefinition> getRouteDefinitions(){
 return Flux.fromIterable(routes.values());
 }
}
 
  InMemoryRouteDefinitionRepository#getRouteDefinitions() 方法的调用,我们已经在 CompositeRouteDefinitionLocator 看到。 InMemoryRouteDefinitionRepository#save() / InMemoryRouteDefinitionRepository#delete() 方法,下面在 GatewayWebfluxEndpoint 可以看到。  org.springframework.cloud.gateway.actuate.GatewayWebfluxEndpoint ,提供 管理 网关的 HTTP API 。代码如下 : 
@RestController
@RequestMapping("${management.context-path:/application}/gateway")
public class GatewayWebfluxEndpoint implements ApplicationEventPublisherAware{
 /**
* 存储器 RouteDefinitionLocator 对象
*/
 private RouteDefinitionWriter routeDefinitionWriter;
 // ... 省略代码
}
 
  @RestController 我们可以得知,GatewayWebfluxEndpoint 是一个 Controller 。 GatewayWebfluxEndpoint 有 两个 HTTP API 调用了 RouteDefinitionWriter 的 两个 方法。
 POST "/routes/{id}" ,保存路由配置,代码如下 : 
@PostMapping("/routes/{id}")
@SuppressWarnings("unchecked")
public Mono<ResponseEntity<Void>> save(@PathVariable String id, @RequestBody Mono<RouteDefinition> route) {
 return this.routeDefinitionWriter.save(route.map(r -> { // 设置 ID
 r.setId(id);
 log.debug("Saving route: " + route);
 return r;
 })).then(Mono.defer(() -> // status :201 ,创建成功。参见 HTTP 规范 :https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
 Mono.just(ResponseEntity.created(URI.create("/routes/"+id)).build())
 ));
}
 
    例如,HTTP 请求如下 :
http POST :8080/application/gateway/routes/apiaddreqhead uri= http://httpbin.org:80 predicates:=’[“Host=**.apiaddrequestheader.org”, “Path=/headers”]’ filters:=’[“AddRequestHeader=X-Request-ApiFoo, ApiBar”]’
 DELETE "/routes/{id}" ,删除路由配置,代码如下 : 
@DeleteMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
 return this.routeDefinitionWriter.delete(Mono.just(id))
 .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) // 删除成功
 .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); // 删除失败
}
 
    使用 InMemoryRouteDefinitionRepository 来维护 RouteDefinition 信息,在网关实例重启或者崩溃后,RouteDefinition 就会丢失。此时我们可以实现 RouteDefinitionRepository 接口 ,以实现例如 MySQLRouteDefinitionRepository 。
通过类似 MySQL 等 持久化 、 可共享 的存储器,也可以带来 Spring Cloud Gateway 实例 集群 获得一致的、相同的 RouteDefinition 信息。
另外,我们看到 RouteDefinitionRepository 初始化的代码如下 :
// GatewayAutoConfiguration.java
@Bean // 4.2
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository(){
 return new InMemoryRouteDefinitionRepository();
}
 
  @ConditionalOnMissingBean(RouteDefinitionRepository.class) ,当 不存在 RouteDefinitionRepository 的 Bean 对象时,初始化 InMemoryRouteDefinitionRepository 。也就是说,我们可以初始化自定义的 RouteDefinitionRepository 以 “注入” 。 比较干爽( 水更 )的一篇文章。
 
 
胖友,分享一波朋友圈可好!