spring boot gateway 過濾器的執行順序

spring boot gateway 過濾器的執行順序

前言

學習官方文檔,發現對於過濾器有分爲三類

  • 默認過濾器
  • 自定義過濾
  • 全局過濾器

於是就有一個疑問,關於這些過濾器的訪問順序是怎樣的,今天就以一個demo來進行測試

準備階段

過濾器工廠類

以此爲模板,複製出幾份就可以了,注意打印信息,可區分就行

public class ExampleGatewayFilterFactory extends AbstractGatewayFilterFactory {

    /**
     * 創造出的過濾器的順序
     */
    private int order;

    /**
     * constructor
     */
    public ExampleGatewayFilterFactory(int order) {
        this.order = order;
    }

    @Override
    public GatewayFilter apply(Object config) {
        return new InnerFilter();
    }

    /**
     * 創建一個內部類,來實現2個接口,指定順序
     */
    private class InnerFilter implements GatewayFilter, Ordered {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println("  pre 自定義過濾器工廠  " + this.getClass().getSimpleName());
            // 在then方法裏的,相當於aop中的後置通知
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.out.println("  post 自定義過濾器工廠 " + this.getClass().getSimpleName());
            }));
        }

        @Override
        public int getOrder() {
            return order;
        }
    }

}

過濾器配置類

這裏我們設置了

  • 2個默認過濾器
  • 2個自定義過濾器,
  • 1個全局過濾器
@SpringBootConfiguration
public class FilterConfig {

    // 以下是全局的過濾器(注意這裏我們保持它爲最高優先級)
    @Bean
    @Order(value = Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter costFilter(){
        return new CostFilter();
    }


    // 以下是自定義的的過濾器工廠

    @Bean
    public GatewayFilterFactory exampleAGatewayFilterFactory(){
        return new ExampleAGatewayFilterFactory(0);
    }

    @Bean
    public GatewayFilterFactory exampleGatewayFilterFactory(){
        return new ExampleGatewayFilterFactory(1);
    }

    // 以下是默認過濾工廠

    @Bean
    public GatewayFilterFactory myDefaultGatewayFilterFactory(){
        return new MyDefaultGatewayFilterFactory(2);
    }

    @Bean
    public GatewayFilterFactory myDefaultAAGatewayFilterFactory(){
        return new MyDefaultAAGatewayFilterFactory(3);
    }
}

springboot啓動類

// 這裏掃描基礎包,可以把其他配置加入進來
@SpringBootApplication(scanBasePackages = {"com.example.gateway"})
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

}

application.yml文件的配置

spring:
  application:
    name: demo-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: to-route
          uri: lb://demo-consumer
          # 例如訪問 localhost:8080/route會路由到demo-consumer的服務下的/route接口
          predicates:
            - Path=/route
        - id: to-account
          uri: lb://demo-consumer
          predicates:
            - Path=/account/v1/**
          filters:
            - name: ExampleA
            - name: Example
      # 默認過濾器
      default-filters:
        - name: MyDefaultAA
        - name: MyDefault

測試

場景一

按照準備階段的配置order順序,來看訪問的結果

  pre 自定義過濾器工廠 AAAA  InnerFilter
  pre 自定義過濾器工廠  InnerFilter
  pre 【默認】過濾器工廠  InnerFilter
  pre 【默認AAA】過濾器工廠  InnerFilter
  pre 全局過濾器  CostFilter
  post 全局過濾器  CostFilter
  post 【默認AAA】過濾器工廠 InnerFilter
  post 【默認】過濾器工廠 InnerFilter
  post 自定義過濾器工廠 InnerFilter
  post 自定義過濾器工廠 AAAA InnerFilter

過濾器的執行順序與堆棧這個數據結構很想,LIFO,gateway中的過濾器只有前置和後置2個生命週期,pre中後觸發的,在post中就先被執行了
從輸出的打印來看,默認過濾器和自定義的過濾器按照我們定義的1 2 3 4的順序,成功的打印了出來,而全局過濾器是在最後才執行

場景二

自定義過濾器和默認過濾器都保留爲相同的order順序

修改如下,都統一爲是0

    @Bean
    public GatewayFilterFactory exampleAGatewayFilterFactory(){
        return new ExampleAGatewayFilterFactory(0);
    }

    @Bean
    public GatewayFilterFactory exampleGatewayFilterFactory(){
        return new ExampleGatewayFilterFactory(0);
    }

    // 以下是默認過濾工廠

    @Bean
    public GatewayFilterFactory myDefaultGatewayFilterFactory(){
        return new MyDefaultGatewayFilterFactory(0);
    }

    @Bean
    public GatewayFilterFactory myDefaultAAGatewayFilterFactory(){
        return new MyDefaultAAGatewayFilterFactory(0);
    }

返回的結果

  pre 【默認AAA】過濾器工廠  InnerFilter
  pre 【默認】過濾器工廠  InnerFilter
  pre 自定義過濾器工廠 AAAA  InnerFilter
  pre 自定義過濾器工廠  InnerFilter
  pre 全局過濾器  CostFilter
  post 全局過濾器  CostFilter
  post 自定義過濾器工廠 InnerFilter
  post 自定義過濾器工廠 AAAA InnerFilter
  post 【默認】過濾器工廠 InnerFilter
  post 【默認AAA】過濾器工廠 InnerFilter

注意到我們前面在yml中配置的過濾器的順序是

          filters:
            - name: ExampleA
            - name: Example
      # 默認過濾器
      default-filters:
        - name: MyDefaultAA
        - name: MyDefault
  1. 這與前面幾行的輸出結果一致,所以如果當優先order一樣的前提下,默認過濾器的執行優先於自定義過濾器,過濾器的執行順序是與你在yml中聲明的順序是一致的。
  2. 全局過濾器依然是最後一個執行的

場景三

我們將自定義過濾器和默認過濾的順序按照穿插的來,即
自定義、默認、自定義、默認

    // 以下是自定義的的過濾器工廠

    @Bean
    public GatewayFilterFactory exampleAGatewayFilterFactory(){
        return new ExampleAGatewayFilterFactory(1);
    }

    @Bean
    public GatewayFilterFactory exampleGatewayFilterFactory(){
        return new ExampleGatewayFilterFactory(3);
    }

    // 以下是默認過濾工廠

    @Bean
    public GatewayFilterFactory myDefaultGatewayFilterFactory(){
        return new MyDefaultGatewayFilterFactory(2);
    }

    @Bean
    public GatewayFilterFactory myDefaultAAGatewayFilterFactory(){
        return new MyDefaultAAGatewayFilterFactory(4);
    }

運行訪問後的執行結果如下

  pre 自定義過濾器工廠 AAAA  InnerFilter
  pre 【默認】過濾器工廠  InnerFilter
  pre 自定義過濾器工廠  InnerFilter
  pre 【默認AAA】過濾器工廠  InnerFilter
  pre 全局過濾器  CostFilter
  post 全局過濾器  CostFilter
  post 【默認AAA】過濾器工廠 InnerFilter
  post 自定義過濾器工廠 InnerFilter
  post 【默認】過濾器工廠 InnerFilter
  post 自定義過濾器工廠 AAAA InnerFilter

可以看到它是按照我們書寫的順序來的


結論

  1. 全局過濾器與其他2類過濾器相比,永遠是最後執行的;它的優先級只對其他全局過濾器起作用
  2. 當默認過濾器與自定義過濾器的優先級一樣時,優先出發默認過濾器,然後纔是自定義過濾器;同類型的過濾器,出發順序與他們在配置文件中聲明的順序一致
  3. 默認過濾器與自定義過濾器使用同樣的order順序空間,即他們會按照各自的順序來進行排序
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章