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類的代碼同上面一樣,不再展示了