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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
}
}

使用

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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容器当中

1
2
3
4
@Bean
public ExampleGatewayFilterFactory exampleGatewayFilterFactory(){
return new ExampleGatewayFilterFactory();
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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方法需要做一些修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@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类的代码同上面一样,不再展示

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2021 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :