目前SpringCloud Gateway只支持配置文件yml、properties和配置文件@Configuration的方式配置路由。这种方式有弊端,就是如果需要变更路由信息,修改路由规则,然后重启Gateway,修改或增加的路由规则才会生效。如果出现该问题,在Gateway重启的这段时间里,所有接入Gateway服务的应用都不可用。这肯定是不可行的。
Gateway默认的配置
¶yml配置文件
¶@Configuration
路由初始化
不管是什么方式配置路由,这些配置最后都会被封装到RouteDefinition中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class RouteDefinition{
private String id;
@NotEmpty
@Valid
private List predicates = new ArrayList<>();
@Valid
private List filters = new ArrayList<>();
@NotNull
private URI uri;
private Map metadata = new HashMap<>();
private int order = 0;
public RouteDefinition(){
}
...
}
一个路由配置就是一个RouteDefinition对象,一个RouteDefinition对应一个ID,如果不设置,默认为uuid,所有路由信息在系统启动的时候被加载进内存里
如图框住的部分就是加载yml文件,它返回PropertiesRouteDefinitionLocator对象,该对象实现RouteDefinitionLocator接口,该接口是路由的装载器1
2
3
4
5public interface RouteDefinitionLocator{
Flux getRouteDefinitions();
}
该接口只有一个方法,就是获取路由配置,该接口有多个实现类,分别对应不同的配置路由的方式
CachingRouteDefinitionLocator -RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取RouteDefinition
RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
初始化顺序是配置文件加载初始化 PropertiesRouteDefinitionLocator–>CompositeRouteDefinitionLocator
存储器中加载初始化RouteDefinitionRepository–>CompositeRouteDefinitionLocator
注册中心加载初始化DiscoveryClientRouteDefinitionLocator–>CompositeRouteDefinitionLocator
而使用存储器中初始化的条件是,没有定义RouteDefinitionRepository1
2
3
4
5@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository(){
return new InMemoryRouteDefinitionRepository();
}
路由配置从数据库中获取
因此,我们可以通过实现RouteDefinitionRepository接口来自定义路由配置的获取方式
¶实现RouteDefinitionRepository接口1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59@Component
public class DBARouteDefinitionRepository implements RouteDefinitionRepository{
@Resource
private GatewayDao gatewayDao;
@Override
public Flux getRouteDefinitions(){
List gatewayRouteEntityList = getRouteConfig();
return Flux.fromIterable(gatewayRouteEntityList);
}
private List getRouteConfig(){
List routesEntities = gatewayDao.queryAllRoutes();
List definitions = new ArrayList<>();
//组装RouteDefinition
for (RoutesEntity entity : routesEntities) {
RouteDefinition definition = new RouteDefinition();
Map predicateParams = new HashMap<>();
PredicateDefinition predicate = new PredicateDefinition();
Map filterParams = new HashMap<>();
FilterDefinition filter = new FilterDefinition();
URI uri = UriComponentsBuilder.fromHttpUrl(entity.getUri()).build().toUri();
predicate.setName("Path");
predicateParams.put("pattern",entity.getPredicates());
predicate.setArgs(predicateParams);
//过滤暂时不写
//filter.setName("StripPrefix");
//TODO 动态过滤
definition.setPredicates(Arrays.asList(predicate));
//definition.setFilters();
definition.setUri(uri);
definition.setId(entity.getRouteId());
definitions.add(definition);
}
return definitions;
}
@Override
public Mono save(Mono route){
return null;
}
@Override
public Mono delete(Mono routeId){
return null;
}
}
¶动态路由1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36@Service
public class DBARouteConfigService implements ApplicationEventPublisherAware{
@Resource
private GatewayDao gatewayDao;
private ApplicationEventPublisher applicationEventPublisher;
public int add(RoutesEntity entity){
gatewayDao.create(entity);
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return 1;
}
public int delete(String routeId){
gatewayDao.deleteByRouteId(routeId);
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return 1;
}
public int update(RoutesEntity entity){
gatewayDao.updateRouteById(entity);
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return 1;
}
/**
* 发布事件
* @param applicationEventPublisher
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher){
this.applicationEventPublisher = applicationEventPublisher;
}
}
在数据库中修改删除路由配置,然后再执行一下RefreshRoutesEvent事件,即可刷新路由配置,无需重启,立刻生效