フィルタータイプ
GlobalFilter:グローバルフィルター。すべてのルートに有効です。GlobalFilterインターフェースを実装することによって作成されました
GatewayFilter:ゲートウェイフィルター。部分フィルターまたはカスタムフィルターとも呼ばれ、このフィルターで構成されたルートにのみ有効です。GatewayFilterFactoryによって作成されました。
フィルタは2回実行され、フィルタは事前と事後に分割されます。
pre:リクエストの前に呼び出されます。
post:応答結果が返されたときに呼び出されます。順序はpreとは完全に逆です。ここでは、フィルターの実行前の順序についてのみ説明し、postを逆にします。
最初に結論について話しましょう
結論として
インターネット上の声明はあまり正確ではありませんが、あまり派手ではありません。
最終的に、それらはすべてOrder値によってソートおよび実行され、Order値が小さいほど、早く実行されます。
ソースコードはorg.springframework.cloud.gateway.handler.FilteringWebHandler#handleメソッドにあります
AnnotationAwareOrderComparator.sort(combined);
不可解な並べ替え状況が発生する理由については、すべて同じOrder値が原因であるか、Order値を生成するためのルールを理解していないことが原因です。以下では、最初に2つのポイントについて説明し、最後にコード検証とソースコード分析を通じて説明します。
注文額が同じ場合
1. 2つのGlobalFilterタイプのフィルターのOrder値が同じ場合、ファイル名に従ってアルファベット順にソートされ、最初のファイル名の優先度が高くなります。
その理由は、パッケージがスキャンされると、ファイルの順序でスキャンされてから、リストコレクションにカプセル化されるためです。Order値で並べ替えるときにOrder値が同じである場合、名のファイル名は次のようになります。まだ1位にランクされています。
2. GlobalFilterタイプとGatewayFilterタイプのフィルター順序値が同じである場合、GlobalFilterタイプの優先度が高くなります。
その理由は、これら2つのフィルターが最終的にフィルターセットにマージされてフィルター呼び出しチェーンを形成するためです。ソースコードは、list.addAll();メソッドaddAll()を介してGatewayFilterタイプのフィルターをGlobalFilterフィルターセットに追加することです。 isメソッドは最後に追加されるため、Order値が同じ場合、GatewayFilterタイプのフィルターは後ろにランク付けされます。
注文値の生成ルール
1. GlobalFilterタイプのフィルターは、Orderedインターフェースを実装するgeOrder()メソッドによって設定されます。
2. GatewayFilterタイプのフィルター、Order値は手動で設定できません。構成ファイルで構成されたフィルター順序によって自動的に生成されます。1から固定され、パッケージが固定されます。たとえば、3つのフィルターが構成されている場合、注文額は上から下の順になります。1、2、3。
コード検証
GlobalFilterフィルターを定義する
@Component
public class GaFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Ga 1");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
@Component
public class GbFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Gb 2");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
@Component
public class GcFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Gc 1");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
GatewayFilterフィルターを定義する
注:簡単にするために、AbstractNameValueGatewayFilterFactoryから直接継承されます。実際の使用は、継承されたクラスを選択する必要があるかどうかによって異なります。
@Component
public class FaGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fa");
return chain.filter(exchange);
};
}
}
@Component
public class FbGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fb");
return chain.filter(exchange);
};
}
}
@Component
public class FcGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fc");
return chain.filter(exchange);
};
}
}
GatewayFilterタイプのフィルターは、このフィルターで構成されたルーティングサービスでのみ有効になるため、ルーティング構成に追加する必要があります。 "=" nとvは、NameValueConfigの値です。ここに記述してください。
routes:
- id: 用户服务
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- Fa=n, v
- Fc=n, v
- Fb=n, v
結果出力
Ga 1
Gc 1
Fa
Gb 2
Fc
Fb
ソースコード分析
サービスが開始されると、org.springframework.cloud.gateway.route.RouteDefinitionRouteLocatorは、ルートで構成されたフィルターをルートのフィルターセットにロードし、Order値をカプセル化します。
private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
List<GatewayFilter> filters = (List)filterDefinitions.stream().map((definition) -> {
// 从过滤器工厂中取出配置了的过滤器封装到路由的过滤器集合中
GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName());
if (factory == null) {
throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
} else {
Map<String, String> args = definition.getArgs();
if (this.logger.isDebugEnabled()) {
this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
}
Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
Object configuration = factory.newConfig();
ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), this.validator);
GatewayFilter gatewayFilter = factory.apply(configuration);
if (this.publisher != null) {
this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
}
return gatewayFilter;
}
}).collect(Collectors.toList());
ArrayList<GatewayFilter> ordered = new ArrayList(filters.size());
// 遍历过滤器集合,封装成带Order值的过滤器集合
for(int i = 0; i < filters.size(); ++i) {
GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i);
if (gatewayFilter instanceof Ordered) {
ordered.add(gatewayFilter);
} else {
// 从1开始递增生成Order值
ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
}
}
return ordered;
}
ゲートウェイをリクエストすると、org.springframework.cloud.gateway.handler.FilteringWebHandlerは、ルート内のフィルターをグローバルフィルターとマージしてカプセル化し、完全なフィルターチェーンを生成します。
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList(this.globalFilters);
// 将路由中的过滤器集合添加到全局过滤器集合
combined.addAll(gatewayFilters);
// 排序算法
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);
}
デバッグ
デバッグデバッグ、つまり並べ替え前のフィルターの順序により、ルートで構成されたGatewayFilterタイプのフィルターがGlobalFilterフィルターセットに追加され、GatewayFilterタイプのフィルターの順序の値が1、2、3であることがわかります。
ソート後、Order値でソートされます。GlobalFilterタイプフィルターのOrder値が同じ場合は、ファイル名でソートされます。GatewayFilteタイプフィルターとGlobalFilterrタイプフィルターのOrder値が同じ場合は、また、GlobalFilterの下でソートされます。
したがって、最終的な実行順序は次のようになります。
プロジェクトで自分でデバッグし、フィルターの実行順序であるorg.springframework.cloud.gateway.handler.FilteringWebHandler#handleで結合された順序を確認できます。