在实际生产环境中为了保证高可靠和高可用,尽量避免重启,如果有新的服务要上线时,可以通过动态路由配置功能上线。
Gateway配置路由主要有两种方式:
而无论是 yml,还是代码配置,启动网关后将无法修改路由配置,如有新服务要上线,则需要先把网关下线,修改 yml 配置后,再重启网关
package org.springframework.cloud.gateway.route :
路由模型:
@Data
public class GatewayRouteDefinition {
//路由的Id
private String id;
//路由断言集合配置
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
//路由过滤器集合配置
private List<GatewayFilterDefinition> filters = new ArrayList<>();
//路由规则转发的目标uri
private String uri;
//路由执行的顺序
private int order = 0;
}
过滤器模型:
@Data
public class GatewayFilterDefinition {
//Filter Name
private String name;
//对应的路由规则
private Map<String, String> args = new LinkedHashMap<>();
}
断言模型:
@Data
public class GatewayPredicateDefinition {
//断言对应的Name
private String name;
//配置的断言规则
private Map<String, String> args = new LinkedHashMap<>();
}
编写动态路由实现类,需实现ApplicationEventPublisherAware接口
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
//增加路由
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "add route success";
}
//更新路由
public String update(RouteDefinition definition) {
try {
delete(definition.getId());
} catch (Exception e) {
return "update fail,not find route routeId: "+definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "update route success";
} catch (Exception e) {
return "update route fail";
}
}
//删除路由
public Mono<ResponseEntity<Object>> delete(String id) {
return this.routeDefinitionWriter.delete(Mono.just(id)).then(Mono.defer(() -> {
return Mono.just(ResponseEntity.ok().build());
})).onErrorResume((t) -> {
return t instanceof NotFoundException;
}, (t) -> {
return Mono.just(ResponseEntity.notFound().build());
});
}
}
编写 Rest接口,通过这些接口实现动态路由功能,注意SpringCloudGateway使用的是WebFlux不要引用WebMvc。
@RestController
@RequestMapping("/route")
public class RouteController {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
//增加路由
@PostMapping("/add")
public String add(@RequestBody GatewayRouteDefinition gwdefinition) {
String flag = "fail";
try {
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
flag = this.dynamicRouteService.add(definition);
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
//删除路由 Mono>
@DeleteMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
try {
return this.dynamicRouteService.delete(id);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
//更新路由
@PostMapping("/update")
public String update(@RequestBody GatewayRouteDefinition gwdefinition) {
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
return this.dynamicRouteService.update(definition);
}
//把传递进来的参数转换成路由对象
private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
RouteDefinition definition = new RouteDefinition();
definition.setId(gwdefinition.getId());
definition.setOrder(gwdefinition.getOrder());
//设置断言
List<PredicateDefinition> pdList=new ArrayList<>();
List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();
for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setArgs(gpDefinition.getArgs());
predicate.setName(gpDefinition.getName());
pdList.add(predicate);
}
definition.setPredicates(pdList);
//设置过滤器
List<FilterDefinition> filters = new ArrayList();
List<GatewayFilterDefinition> gatewayFilters = gwdefinition.getFilters();
for(GatewayFilterDefinition filterDefinition : gatewayFilters){
FilterDefinition filter = new FilterDefinition();
filter.setName(filterDefinition.getName());
filter.setArgs(filterDefinition.getArgs());
filters.add(filter);
}
definition.setFilters(filters);
URI uri = null;
if(gwdefinition.getUri().startsWith("http")){
uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
}else{
// uri为 lb://consumer-service 时使用下面的方法
uri = URI.create(gwdefinition.getUri());
}
definition.setUri(uri);
return definition;
}
}
URL : http://localhost:9004/route/add
参数:
{
"id": "routeadd",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/ccc/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"parts": "1"
}
},
{
"name":"RequestPath",
"args":{
"name":"lisi",
"path":"/baidu"
}
}
],
"uri": "https://www.baidu.com",
"order": 1
}
Spring Cloud Gateway 提供了 Endpoint
端点,暴露路由信息,有获取所有路由、刷新路由、查看单个路由、删除路由等方法,源码在 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 中,想访问端点中的方法需要添加 spring-boot-starter-actuator 注解,并在配置文件中暴露所有端点。
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<!-- actuator是监控系统健康情况的工具。-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# 暴露端点 需要添加 actuator 依赖, 有获取所有路由、刷新路由、查看单个路由、删除路由等方法
# http://localhost:9004/actuator/gateway/routes 查看application.yml中的Gateway的routes信息
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
URL:http://localhost:9004/route/update
将Path
的断言参数由/ccc/**
修改为/bbb/**
参数:
{
"id": "routeadd",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/bbb/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"parts": "1"
}
},
{
"name":"RequestPath",
"args":{
"name":"lisi",
"path":"/baidu"
}
}
],
"uri": "https://www.baidu.com",
"order": 1
}
URL: http://localhost:9004/route/routes/routeadd
https://gitee.com/L1692312138/spring-cloud-alibaba
https://blog.csdn.net/zhuyu19911016520/article/details/86557165