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順序空間,即他們會按照各自的順序來進行排序


免責聲明!

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



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