動態路由修改
當我們看了Spring Cloud Gateway的示例代碼,和一些網上的入門教程之後,會發現大多是Spring Cloud Gateway — 網關基本功能API暴露說道的三種方法:1.本地配置文件;2.java代碼builder.routes().route().build(); 3.服務自動發現。
服務自動發現方法能夠做到後端服務ip變化時自動更新,能夠做到上游服務的動態。另外兩種方式都是純靜態,需要重新啓動網關服務修改才能生效。
上述方式都不能完全滿足生產需要,一般來說作爲生產上的通用網關要求有路由動態修改能力,不重啓網關服務即可即使生效。無論是新增路由、或者是修改路由的過濾規則,添加過濾器都可以不重啓網關生效。
內置的動態路由
Spring Cloud Gateway內置了一個動態路由類InMemoryRouteDefinitionRepository
。這是一個使用內存存儲路由的類,支持acurator接口對路由進行增刪改查,但是當網關重啓之後所有的內存路由都會消失,也就是說它沒有持久化能力。
雖然InMemoryRouteDefinitionRepository
沒有達到生產級動態路由修改的需求,但是它提供了一種思路,起到了示例作用。如果需要實現自己的可持久化動態路由,可以仿照InMemoryRouteDefinitionRepository
的路由解析加載能力,以及更新方式實現在即的動態路由。
基於分佈式配置的動態路由
基於分佈式配置可能是一種最簡單便捷的路由動態修改能力了,這裏展示基於spring cloud config實現Spring Cloud Gateway動態路由修改。
/**
* a route definition locator, that locate route definition from remote config server or local properties file.
* route definition is json value, not yaml value, e.g.
* "route-definitions=[{\"id\": \"websocket_test\",\"uri\": \"ws://localhost:9000\",\"order\": 9000,\"predicates\":[\"Path=/echo\"],\"filters\":[\"AddRequestHeader=x-tt-token, 123456\"]}]"
* or
* "route-definitions=[{\"id\": \"websocket_test\",\"uri\": \"ws://localhost:9000\",\"order\": 9000,\"predicates\":[{\"name\":\"Path\", \"args\":{\"_genkey_0\":\"/echo\"}}],\"filters\":[{\"name\":\"AddRequestHeader\", \"args\":{\"_genkey_0\":\"x-tt-token\",\"_genkey_1\":\"123456\"}}]}]"
*
* compare to spring cloud gateway's default InMemoryRouteDefinitionRepository, route definitions could be loaded when program's startup.
*
* to do this, there is another way. define a bean and load remote route definitions to InMemoryRouteDefinitionRepository when program's startup.
* otherwise, you should implement ApplicationListener<ApplicationEvent>. when refresh event emited, remote route definitions should be reloaded
* into InMemoryRouteDefinitionRepository.
*/
public class ConfigServerRouteDefinitionLocator implements RouteDefinitionLocator {
@Value("${route-definitions}")
private String routeDefinitions;//a json string, contains route definition lists
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
ObjectMapper mapper = new ObjectMapper();
List<RouteDefinition> rdList = null;
try {
System.out.println(routeDefinitions);
rdList = mapper.readValue(routeDefinitions, new TypeReference<List<RouteDefinition>>() { });
return Flux.fromArray(rdList.toArray(new RouteDefinition[]{}));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Flux.empty();
}
}
方法很簡單,只需要在config server裏增加一個路由的配置項即可。config server可以調用Spring Cloud Gateway的路由更新接口/refresh
,路由配置就會自動更新。
如果要實現更復雜的控制邏輯,比如路由配置的路由校驗、版本控制、灰度發佈等其他功能,可以在定義自己的refresh接口和管理後臺進行控制。
其他方式
如果時間允許,可以使用其他存儲方式實現路由動態修改能力。可以參考以下文章:
基於Redis實現動態路由修改
基於Redis實現動態路由修改-其中的金絲雀是對上游的金絲雀發佈,不是對網關自身的金絲雀控制,這種用法一般不太常見