一、Gateway路由主要有兩種方式
1、用yml配置文件
routes:
- id: ijep-service-sys #基礎(chǔ)服務(wù)
uri: lb://ijep-service-sys
predicates:
- Path=/api/sys/**
filters:
- StripPrefix=2
2、寫在代碼里

無論是哪一種,在啟動網(wǎng)關(guān)后將無法修改路由配置,如有新服務(wù)要上線,則需要先把網(wǎng)關(guān)下線,修改 yml 配置后,再重啟網(wǎng)關(guān)。
二、動態(tài)路由解析
Gateway網(wǎng)關(guān)啟動時,路由信息默認(rèn)會加載內(nèi)存中,路由信息被封裝到 RouteDefinition 對象中,配置多個RouteDefinition組成Gateway的路由系統(tǒng)。
package org.springframework.cloud.gateway.route;
@Validated
public class RouteDefinition {
@NotEmpty
private String id = UUID.randomUUID().toString();
@NotEmpty
@Valid
private List<PredicateDefinition> predicates = new ArrayList<>();
@Valid
private List<FilterDefinition> filters = new ArrayList<>();
@NotNull
private URI uri;
private int order = 0;
public RouteDefinition() {
}
.....此處省略......
}
- RouteDefinition中的字段與上面代碼配置方式比較對應(yīng)
package org.springframework.cloud.gateway.route;
import reactor.core.publisher.Flux;
/**
* @author Spencer Gibb
*/
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
*RouteDefinitionLocator是個接口,在org.springframework.cloud.gateway.route包下,如果想查看網(wǎng)關(guān)中所有的路由信息,可以調(diào)用此方法;后面還有另外一種查看方式,是Spring Cloud Gateway 的Endpoint端點提供的方法
三、Gateway Endpoint 端點
Endpoint 端點有暴露路由信息、獲取所有路由、刷新路由、查看單個路由、刪除路由等方法,源碼在 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 中,訪問端點中的方法需要修改pom和配置文件:
*添加pom文件依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
*yml配置
# 暴露端點
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
四、動態(tài)路由實現(xiàn)
準(zhǔn)備:
* Spring Cloud:Greenwich.SR1
* Spring Boot: 2.1.1.RELEASE
* 注冊中心(Consul)
* 網(wǎng)關(guān)Gateway
* 業(yè)務(wù)服務(wù)(ijep-service-sys)
1、創(chuàng)建路由模型
*過濾器模型
public class GatewayFilterDefinition {
//Filter Name
private String name;
//對應(yīng)的路由規(guī)則
private Map<String, String> args = new LinkedHashMap<>();
......此處省略Get、Set方法......
}
*路由斷言模型
public class GatewayPredicateDefinition {
//斷言對應(yīng)的Name
private String name;
//配置的斷言規(guī)則
private Map<String, String> args = new LinkedHashMap<>();
......此處省略Get、Set方法......
}
*路由模型
public class GatewayRouteDefinition {
//路由的Id
private String id;
//路由斷言集合配置
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
//路由過濾器集合配置
private List<GatewayFilterDefinition> filters = new ArrayList<>();
//路由規(guī)則轉(zhuǎn)發(fā)的目標(biāo)uri
private String uri;
//路由執(zhí)行的順序
private int order = 0;
......此處省略Get、Set方法......
}
2、編寫態(tài)路由實現(xiàn)類,實現(xiàn)ApplicationEventPublisherAware接口
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware{
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
/**
* 增加路由
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
/**
* 更新路由
* @param definition
* @return
*/
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 "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 刪除路由
* @param id
* @return
*/
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());
});
}
}
3、編寫API接口,實現(xiàn)動態(tài)路由功能
@RestController
@RequestMapping("/api/route")
public class RouteRestController {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
/**
* 增加路由
* @param gatewayRouteDefinition 路由模型
* 報文:{"filters":[{"name":"StripPrefix","args":{"_genkey_0":"2"}}],"id":"ijep-service-sys-hyk11","uri":"lb://ijep-service-sys","order":2,"predicates":[{"name":"Path","args":{"_genkey_0":"/api/hyk11/**"}}]}
* @return
*/
@PostMapping("/add")
public RestResponse add(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) {
String flag = "fail";
try
{
RouteDefinition definition = assembleRouteDefinition(gatewayRouteDefinition);
flag = this.dynamicRouteService.add(definition);
} catch (Exception e) {
e.printStackTrace();
}
return RestResponseBuilder.restResponse().data(flag).build();
}
/**
* 更新路由
* @param gatewayRouteDefinition 路由模型
* 報文:{"filters":[{"name":"StripPrefix","args":{"_genkey_0":"2"}}],"id":"ijep-service-sys-hyk11","uri":"lb://ijep-service-sys","order":2,"predicates":[{"name":"Path","args":{"_genkey_0":"/api/hyk11/**"}}]}
* @return
*/
@PostMapping("/update")
public RestResponse update(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) {
RouteDefinition definition = assembleRouteDefinition(gatewayRouteDefinition);
String flag = this.dynamicRouteService.update(definition);
return RestResponseBuilder.restResponse().data(flag).build();
}
/**
* 刪除路由
* @param id 路由Id
* @return
*/
@DeleteMapping("/routes/{id}")
public RestResponse delete(@PathVariable String id) {
Mono<ResponseEntity<Object>> responseEntityMono = this.dynamicRouteService.delete(id);
return RestResponseBuilder.restResponse().data(responseEntityMono).build();
}
/**
* 把傳遞進來的參數(shù)轉(zhuǎn)換成路由對象
* @param gatewayRouteDefinition 路由模型
* @return
*/
private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gatewayRouteDefinition) {
RouteDefinition definition = new RouteDefinition();
definition.setId(gatewayRouteDefinition.getId());
definition.setOrder(gatewayRouteDefinition.getOrder());
//設(shè)置斷言
List<PredicateDefinition> pdList = new ArrayList<>();
List<GatewayPredicateDefinition> gatewayPredicateDefinitionList = gatewayRouteDefinition.getPredicates();
for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setArgs(gpDefinition.getArgs());
predicate.setName(gpDefinition.getName());
pdList.add(predicate);
}
definition.setPredicates(pdList);
//設(shè)置過濾器
List<FilterDefinition> filters = new ArrayList();
List<GatewayFilterDefinition> gatewayFilters = gatewayRouteDefinition.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(gatewayRouteDefinition.getUri().startsWith("http")){
uri = UriComponentsBuilder.fromHttpUrl(gatewayRouteDefinition.getUri()).build().toUri();
}else{
// uri為 lb://consumer-service 時使用下面的方法
uri = URI.create(gatewayRouteDefinition.getUri());
}
definition.setUri(uri);
return definition;
}
}
4、啟動網(wǎng)關(guān)服務(wù)
查詢所有的路由地址信息,訪問地址:http://localhost:9000/actuator/gateway/routes

5、訪問業(yè)務(wù)接口(ApiPost)

6、新增路由信息(ApiPost)

7、新增后,訪問業(yè)務(wù)接口(ApiPost)

項目地址:無權(quán)訪問