spring cloud gateway 自定义GatewayFilterFactory

spring cloud gateway提供了很多内置的过滤器,那么因为需求的关系,需要自定义实现,并且要可配置,在一番折腾之后,总算是解决了,那么久记录下来

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

首先来看我们的自定义的过滤器工厂类代码

/**
 * Description: it's purpose...
 *
 * @author a 2019-5-22
 * @version 1.0
 */
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;
        }
    }
}

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

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

然后是yaml的配置,这里需要注意的是,之前我一直失败,在调用gateway会报告找不到对应的过滤率,这是因为命名导致的
springboot约定过滤器的前缀为配置的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类的代码同上面一样,不再展示了
posted @ 2019-05-23 08:44  myCodeLikeShit  阅读(13370)  评论(1编辑  收藏  举报