Spring Cloud Gateway自定义GatewayFilterFactory

GatewayFilterFactory

Spring Cloud Gateway提供了很多内置的过滤器,那么因为需求的关系,需要自定义实现,并且要可配置

对于自定义的factory,我们可以选择去实现接口或继承已有的抽象类,相关的接口是GatewayFilterFactory,而Spring Boot默认帮我们实现的抽象类是AbstractGatewayFilterFactory

使用参考:http://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.0.0.RELEASE/multi/multi__developer_guide.html#_writing_custom_gatewayfilter_factories

In order to write a GatewayFilter you will need to implement GatewayFilterFactory. There is an abstract class called AbstractGatewayFilterFactory which you can extend.

  • PreGatewayFilterFactory.java
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
    public PreGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling change.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
    public static class Config {
        //Put the configuration properties for your filter here
    }
}
  • PostGatewayFilterFactory.java
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
    public PostGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpReponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }
    public static class Config {
        //Put the configuration properties for your filter here
    }
}

使用

首先自定义的过滤器工厂类代码

public class ExampleGatewayFilterFactory extends AbstractGatewayFilterFactory<ExampleGatewayFilterFactory.Config> {

    /**
     * 定义可以再yaml中声明的属性变量
     */
    private static final String TYPE = "type";
    private static final String OP = "op";

    /**
     * constructor
     */
    public ExampleGatewayFilterFactory(){
        // 这里需要将自定义的config传过去,否则会报告ClassCastException
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(TYPE, OP);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            boolean root = "root".equals(config.getOp());
            if (root){
                LogUtil.info("GatewayFilter root");
            }
            else {
                LogUtil.info("GatewayFilter customer");
            }
            // 在then方法里的,相当于aop中的后置通知
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                // do something
            }));
        });
    }

    /**
     * 自定义的config类,用来设置传入的参数
     */
    public static class Config {

        /**
         * 过滤类型
         */
        private String type;

        /**
         * 操作
         */
        private String op;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getOp() {
            return op;
        }

        public void setOp(String op) {
            this.op = op;
        }
    }
}

因为使用的是Spring Boot,那么需要在启动类里,将这个工厂注入到Spring容器当中

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

然后是yaml的配置,这里需要注意的是,之前我一直失败,在调用gateway会报告找不到对应的过滤器,这是因为命名导致的Spring Boot约定过滤器的前缀为配置的name,而后面最好统一都是GatewayFilterFactory

spring:
  application:
    name: demo-gateway
  cloud:
    gateway:
      routes:
        - id: custom
          uri: lb://demo-consumer
          predicates:
            - Path=/account/v1/**
          filters:
            - name: Example
              args:
                op: root
                type: he

到这里,过滤器的编写与配置就完成了,然后启动项目,访问/account/v1/test,就会在日志里看到在过滤器中打印的信息

注意我们通过这种工厂创建出来的过滤器是没有指定order的,会被默认设置为是0,配置在yml文件中,则按照其书写的顺序来执行。如果想要在代码中设置顺序,工厂的apply方法需要做一些修改

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

/**
 * 创建一个内部类,来实现2个接口,指定顺序
 */
private class InnerFilter implements GatewayFilter, Ordered {

    private Config config;

    InnerFilter(Config config) {
        this.config = config;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("  pre 自定义过滤器工厂 AAAA  " + this.getClass().getSimpleName());
        boolean root = "root".equals(config.getOp());
        if (root) {
            System.out.println("  is root ");
        } else {
            System.out.println("  is no root ");
        }
        // 在then方法里的,相当于aop中的后置通知
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            System.out.println("  post 自定义过滤器工厂 AAAA " + this.getClass().getSimpleName());
        }));
    }

    @Override
    public int getOrder() {
        return -100;
    }
}

// config类的代码同上面一样,不再展示

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/26/spring-cloud-gateway-custom-gatewayfilterfactory/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Spring Cloud Gateway自定义GatewayFilterFactory
GatewayFilterFactory Spring Cloud Gateway提供了很多内置的过滤器,那么因为需求的关系,需要自定义实现,并且要可配置 对于自定义的factory,我们可以选择……
<<上一篇
下一篇>>
文章目录
关闭
目 录