gateway&reactive(響應式流)函數編程的webflux


  springcloud.gateway是springcloud2的全新項目,該項目提供了一個構建在spring生態之上的API網關,包括spring5,springboot2,projectReactor。gateway旨在提高一種簡單而有效的途徑來轉發請求,並為他們提供橫切關注點,如安全性,監控/指標和彈性。在之前springcloud提供的網關是zull,zuul基於servlet2.5,使用阻塞架構,不支持長連接。zuul和negix相似,除了編程語言不同,zuul已經發布了zuul2,支持長連接,非阻塞,但是springcloud還沒有整合。

項目構建:

  引入gateway和eureka依賴,gateway的網關提供了路由配置,路由斷言,過濾器等功能。

一, 路由斷言:

  路由斷言接口由函數式接口RouterFunction接口提供支持,通過RouterFunctions的靜態route方法來實現,如下:

 1 public static <T extends ServerResponse> RouterFunction<T> route(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
 2         return new RouterFunctions.DefaultRouterFunction(predicate, handlerFunction);
 3     }
 4 
 5 private static final class DefaultRouterFunction<T extends ServerResponse> extends RouterFunctions.AbstractRouterFunction<T> {
 6         private final RequestPredicate predicate;
 7         private final HandlerFunction<T> handlerFunction;
 8 
 9         public DefaultRouterFunction(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
10             super(null);
11             Assert.notNull(predicate, "Predicate must not be null");
12             Assert.notNull(handlerFunction, "HandlerFunction must not be null");
13             this.predicate = predicate;
14             this.handlerFunction = handlerFunction;
15         }
16 
17         public Mono<HandlerFunction<T>> route(ServerRequest request) {
18             if (this.predicate.test(request)) {
19                 if (RouterFunctions.logger.isTraceEnabled()) {
20                     String logPrefix = request.exchange().getLogPrefix();
21                     RouterFunctions.logger.trace(logPrefix + String.format("Matched %s", this.predicate));
22                 }
23 
24                 return Mono.just(this.handlerFunction);
25             } else {
26                 return Mono.empty();
27             }
28         }
29 
30         public void accept(RouterFunctions.Visitor visitor) {
31             visitor.route(this.predicate, this.handlerFunction);
32         }
33     }
    private abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> 

  而生成需要兩個參數他們分別是:RequestPredicate  predicate和 HandlerFunction<T>  handlerFunction。

predicate由RequestPredicates.path()產生,handlerFunction是接口HandlerFunction<T>的函數實現類,該類只有一個方法:Mono<T> handle(ServerRequest var1)。

  所以添加路由斷言的配置類方法如下:

1 @Bean//路由斷言
2     public RouterFunction<ServerResponse> doRouterFunction(){
3         RouterFunction route = RouterFunctions.route(RequestPredicates.path("/test"),
4                 request -> ServerResponse.ok().body(BodyInserters.fromValue("this is ok")));
5         return route;
6     }

  此時路由斷言的作用是當請求的路徑是/test時,直接返回狀態嗎200,且響應體為this is ok。

為什么呢?

@FunctionalInterface
public interface HandlerFunction<T extends ServerResponse> {
    Mono<T> handle(ServerRequest var1);
}
下圖的類都在org.springframework.web.reactive包下:

 

 從上面可以看出,serverResponse持有serverHttpResponse,而serverHttpResponse持有HttpServletResponse。所以這就是webflux的reactive響應式流編程實現流程。

 二,過濾器:

  網關經常要做的是對路由請求進行過濾,對符合條件的請求進行一些操作,如增加請求頭,增加請求參數,增加響應頭和斷路器等功能。這個功能通過函數接口RouteLocator實現,RouteLocator通過RouteLocatorBuilder來獲得:

 1   @Bean//過濾器
 2     public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
 3         return builder.routes().route(
 4 
 5                 r -> r.path("/baidu")
 6                         .filters(f -> f.addResponseHeader("X-AnotherHeader","baz"))  
7
                  .uri("http://www.baidu.com")
8

9
    ).build();
10 }

RouteLocatorBuilder.Builder.routes就是路由表,如下圖:

 具體類調用流程如下:

 1 public RouteLocatorBuilder.Builder routes() {
 2         return new RouteLocatorBuilder.Builder(this.context);
 3     }
 4 
 5 public RouteLocatorBuilder.Builder route(Function<PredicateSpec, AsyncBuilder> fn) {
 6             AsyncBuilder routeBuilder = (AsyncBuilder)fn.apply((new RouteLocatorBuilder.RouteSpec(this)).randomId());
 7             this.add(routeBuilder);
 8             return this;
 9         }
10 
11  void add(AsyncBuilder route) {
12             this.routes.add(route);
13         }
14 
15 public RouteLocator build() {
16             return () -> {
17                 return Flux.fromIterable(this.routes).map((routeBuilder) -> {
18                     return routeBuilder.build();
19                 });
20             };
21         }

  上面第5行的意思是Builder.route(Function<PredicateSpec, AsyncBuilder> fn)函數需要一個AsyncBuilder,這個AsyncBuilder是org.springframework.cloud.gateway.route.Route.AsyncBuilder,即route的異步構造器,第6行得到了這個異步構造器,第七,八行加到了Builder.routes集合中,並返回自己,然后調用自己的build方法,Flux是Reactive提供的返回結果工具類,原來返回User的話,那現在就返回Mono<User>;原來返回List<User>的話,那現在就返回Flux<User>。第18行調用build構造route。

   我們需要一個asyncbuilder,所以需要實現Function接口,如下:

  r -> r.path("/baidu").filters(f -> f.addRequestHeader("X-AnotherHeader","baz")).uri("http://www.baidu.com")
  上述方法體會最終得到一個asyncbuilder,然后開始上述帶顏色部分的內容。上面的功能就是當請求路徑中有
baidu,就在返回頭上加上一個屬性,然后轉到該http://www.baidu.com地址。

 三,網關與服務中心結合

 1 spring:
 2   application:
 3     name: gateway #hystrix服務類型
 4   cloud:
 5     gateway:
 6       locator:
 7         enabled: true #開啟gateway和eureka的結合
 8       routes:
 9         - id: service_eureka-service1 #id
10           uri: lb://eureka-service1 #服務
11           predicates:
12           - Path=/service_eureka-service1/**  #匹配路徑
13           filters:
14           - StripPrefix=1 #使用路徑過濾器去掉第一部分前綴 即去除service_eureka-service1這一部分

下面是service1的controller:

  

啟動service1和gateway兩個服務,注冊到eureka,然后訪問:

 ok,先到這里,源碼后續再補充。

參考文章:https://blog.csdn.net/get_set/article/details/79480233 這兄弟的文章真不錯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM