Gateway動態(tài)路由實現(xiàn)

一、Gateway路由主要有兩種方式

1、用yml配置文件
  routes:
    - id: ijep-service-sys  #基礎(chǔ)服務(wù)
      uri: lb://ijep-service-sys
      predicates:
        - Path=/api/sys/**
      filters:
        - StripPrefix=2
2、寫在代碼里
image.png

無論是哪一種,在啟動網(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

image.png

5、訪問業(yè)務(wù)接口(ApiPost)
image.png
6、新增路由信息(ApiPost)
image.png
7、新增后,訪問業(yè)務(wù)接口(ApiPost)
image.png

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容