目录
1、基于数据库或者一些缓存组件
1.1 AbstractGatewayControllerEndpoint
1.2 InMemoryRouteDefinitionRepository
1.3 自定义routeDefinition存储器实现动态
刷新路由
1、基于数据库或者一些缓存组件
根据之前的源码的理解,我们可以看到gateway是要先加载routeDefinition,然后再转换成对应的route对象。而对应的接口就是RouteDefinitionLocator,我们查看它的子类 发现有个子类叫RouteDefinitionRepository,我们通过名字可以得知它其实就是DAO层的接口,同时RouteDefinitionRepository还继承了RouteDefinitionWriter。当第一次看时我不知道这个具体是做上面的,只是从名字和方法名看出是做routeDefinition的保存和删除的。然后通过查找find链,发现是在 AbstractGatewayControllerEndpoint 调用的。
1.1 AbstractGatewayControllerEndpoint
它有两个子类,都是controller,也就是当我们访问http://localhost:9001/actuator/gateway/routes 本地gateway链接时的处理层。
它有两个方法:
@PostMapping("/routes/{id}")
@SuppressWarnings("unchecked")
public Mono> save(@PathVariable String id, @RequestBody RouteDefinition route) {
return Mono.just(route).doonNext(this::validateRouteDefinition)
.flatMap(routeDefinition -> this.routeDefinitionWriter.save(Mono.just(routeDefinition).map(r
@DeleteMapping("/routes/{id}")
public Mono> 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()));
}
所以我们可以通过 post -> {baseUrl}/routes/{id} 进行保存路由,delete-> {baseUrl}/routes/{id} 删除路由。
1.2 InMemoryRouteDefinitionRepository
我们查看RouteDefinitionRepository发现它有个子类,也是在GatewayAutoConfiguration中进行初始化的。所以gateway给我们提供了默认的routeDefinition存储器,但是它是基于内存的,而且默认它是不加载路由信息的。且只有当没有其他 RouteDefinitionRepository存储器才会使用它。
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
1.3 自定义routeDefinition存储器实现动态
我是基于内存做的,正常应该是基于redis或者mysql
import com.google.common.collect.Lists;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class MyRouteDefinitionLocator implements RouteDefinitionRepository {
static List routeDefinitionList = new ArrayList<>(2);
static {
for (int i = 0; i < 2; i++) {
String routeId = "my_" + i;
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(routeId);
routeDefinition.setUri(URI.create("https://blog.csdn.net/qGANG/article/details/12350695" + i));
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setName("Path");
predicateDefinition.addArg("pattern", "/ourGateway" + i + "/**");
routeDefinition.setPredicates(Lists.newArrayList(predicateDefinition));
routeDefinitionList.add(routeDefinition);
}
}
@Override
public Flux getRouteDefinitions() {
return Flux.fromIterable(routeDefinitionList);
}
@Override
public Mono save(Mono route) {
String routeId = "my_" + System.currentTimeMillis();
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(routeId);
routeDefinition.setUri(URI.create("https://blog.csdn.net/qGANG/article/details/123506950"));
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setName("Path");
predicateDefinition.addArg("pattern", "/ourGateway" + RandomUtils.nextInt(5, 1000) + "/**");
routeDefinition.setPredicates(Lists.newArrayList(predicateDefinition));
return Mono.empty();
}
@Override
public Mono delete(Mono routeId) {
routeId.subscribe(id -> {
routeDefinitionList = routeDefinitionList.stream().filter(routeDefinition -> !StringUtils.equals(id, routeDefinition.getId())).collect(Collectors.toList());
});
return Mono.empty();
}
}
创建好后可以先debug看看初始化时
因为我是集成了nacos配置中心的,所以还会有其他route,但是我们自定义new出的route已经装载进了route集合。
看到可以正常使用。
删除
我们测下删除功能
发起http请求后,我们马上查看路由列表,发现我们想要删除的路由还是存在的,delete也没有报错,为什么呢? 我们知道,这个删除只是在内存里删除了我们的routedefinition,路由列表是经过转化的route对象,所以如果不触发重新加载routes的话,肯定是不起作用的。
刷新路由
解决方案1:
因为我已经集成了nacos,目前nacos是有个任务,默认30000毫秒会从nacos server拉取注册中心服务并发起HeartbeatEvent事件,而RouteRefreshListener监听到此事件后会发起RefreshRoutesEvent,就会重新加载routes了,路由也就刷新了。
这里也就造成了路由的刷新会有些延迟,但是问题不大。
解决方案2:
AbstractGatewayControllerEndpoint给我们提供了手动刷新路由的方法
@PostMapping("/refresh")
public Mono refresh() {
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return Mono.empty();
}
也就是我们在删除路由后,可以立即调用刷新方法,它的底层原理也是发起refresh路由事件。



