Spring Cloud Gateway 源码剖析之Filter Chain过滤器链

欢迎大家关注我的微信公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

一、前言

前几篇我们讲了 Gateway 相应的初始化、路由相关模型以及 Predicate 谓词详解,这一篇我们再来讲一下 Filter Chain 过滤器链,讲完这一篇,相信你对 Gateway 源码整体设计思想有个深刻的体会了,后续你想去抠细节也不是什么难事了。前几篇可以回顾下:

Spring Cloud Gateway 源码剖析之配置初始化
Spring Cloud Gateway 源码剖析之Route数据模型
Spring Cloud Gateway 源码剖析之Predicate谓词详解

回顾完了我们再来看一张 Spring Cloud Gateway 的整体流程图,相信一直看完这个系列的很快的就能知道上一篇我们讲到了 Predicate 断言这一块,如果 Handler Mapping 匹配成功则会通过 GatewayWebHandler 创建请求对应的 Route 对应的 Filter Chain 来进行处理请求。我们按照这个流程图来看的话,接下来要讲的是通过网关自定义的 WebHandler 来处理请求,这里就来讲一下最重要 FilteringWebHandler 过滤器链。
在这里插入图片描述

二、FilteringWebHandler

// org.springframework.cloud.gateway.handler.FilteringWebHandler
/**
 * 通过过滤器处理web请求的处理器
 */
public class FilteringWebHandler implements WebHandler {
    protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);
    /**
	 * 全局过滤器
	 */
    private final List<GatewayFilter> globalFilters;

    public FilteringWebHandler(List<GlobalFilter> globalFilters) {
        this.globalFilters = loadFilters(globalFilters);
    }

	/**
	 * 组成过滤链
	 * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
	 */
    private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
        return (List)filters.stream().map((filter) -> {
            FilteringWebHandler.GatewayFilterAdapter gatewayFilter = new FilteringWebHandler.GatewayFilterAdapter(filter);
            // 当 GlobalFilter 子类实现了 org.springframework.core.Ordered 接口,在委托一层 OrderedGatewayFilter 。
			// 这样 AnnotationAwareOrderComparator#sort(List) 方法好排序。
            if (filter instanceof Ordered) {
                int order = ((Ordered)filter).getOrder();
                return new OrderedGatewayFilter(gatewayFilter, order);
            } else {
                return gatewayFilter;
            }
        }).collect(Collectors.toList());
    }
	
	// 按照过滤链的顺序依次执行
    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);
    }

	...
}

FilteringWebHandler 的执行顺序:

  • 构建一个包含全局过滤器的集合(combined)
  • 获取上下文中的路由信息 GATEWAY_ROUTE_ATTR
  • 将路由里的过滤器添加到集合中(combined)
  • 对过滤器集合进行排序操作
  • 通过过滤器集合组装过滤器链表,并进行调用(DefaultGatewayFilterChain 与 Servlet 中的 FilterChain 的原理是一致的)
  • 通过过滤器来处理请求到具体业务服务

2.1 GatewayFilter 与 GlobalFilter 的关系

private final List<GatewayFilter> globalFilters;

public FilteringWebHandler(List<GlobalFilter> globalFilters) {
    this.globalFilters = loadFilters(globalFilters);
}

2.1.1 GatewayFilter 网关过滤器接口

public interface GatewayFilter extends ShortcutConfigurable {
    String NAME_KEY = "name";
    String VALUE_KEY = "value";

    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

GatewayFilter 有三种类型的子类实现

  • OrderedGatewayFilter :有序的网关过滤器实现类。在 FilterChain 里,过滤器数组首先会按照 order 升序排序,按照顺序过滤请求。

    public class OrderedGatewayFilter implements GatewayFilter, Ordered {
    	// 委托的 GatewayFilter
        private final GatewayFilter delegate;
        // order代表顺序
        private final int order;
    
        public OrderedGatewayFilter(GatewayFilter delegate, int order) {
            this.delegate = delegate;
            this.order = order;
        }
    
        public GatewayFilter getDelegate() {
            return this.delegate;
        }
    
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return this.delegate.filter(exchange, chain);
        }
    
        public int getOrder() {
            return this.order;
        }
    
        public String toString() {
            StringBuilder sb = new StringBuilder("OrderedGatewayFilter{");
            sb.append("delegate=").append(this.delegate);
            sb.append(", order=").append(this.order);
            sb.append('}');
            return sb.toString();
        }
    }
    
  • GatewayFilterAdapter:网关过滤器适配器。在 GatewayFilterChain 使用 GatewayFilter 过滤请求,所以通过 GatewayFilterAdapter 将 GlobalFilter 适配成 GatewayFilter。

    private static class GatewayFilterAdapter implements GatewayFilter {
    	// 委托的 GlobalFilter
        private final GlobalFilter delegate;
    
        public GatewayFilterAdapter(GlobalFilter delegate) {
            this.delegate = delegate;
        }
    
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return this.delegate.filter(exchange, chain);
        }
    
        public String toString() {
            StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");
            sb.append("delegate=").append(this.delegate);
            sb.append('}');
            return sb.toString();
        }
    }
    
  • ModifyResponseGatewayFilter:用于修改 Response

    public class ModifyResponseGatewayFilter implements GatewayFilter, Ordered {
        private final ModifyResponseBodyGatewayFilterFactory.Config config;
    
        public ModifyResponseGatewayFilter(ModifyResponseBodyGatewayFilterFactory.Config config) {
            this.config = config;
        }
    
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    Class inClass = ModifyResponseGatewayFilter.this.config.getInClass();
                    Class outClass = ModifyResponseGatewayFilter.this.config.getOutClass();
                    String originalResponseContentType = (String)exchange.getAttribute("original_response_content_type");
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.add("Content-Type", originalResponseContentType);
                    ModifyResponseBodyGatewayFilterFactory.ResponseAdapter responseAdapter = ModifyResponseBodyGatewayFilterFactory.this.new ResponseAdapter(body, httpHeaders);
                    DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
                    Mono modifiedBody = clientResponse.bodyToMono(inClass).flatMap((originalBody) -> {
                        return ModifyResponseGatewayFilter.this.config.rewriteFunction.apply(exchange, originalBody);
                    });
                    BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
                    CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());
                    return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
                        Flux<DataBuffer> messageBody = outputMessage.getBody();
                        HttpHeaders headers = this.getDelegate().getHeaders();
                        if (!headers.containsKey("Transfer-Encoding")) {
                            messageBody = messageBody.doOnNext((data) -> {
                                headers.setContentLength((long)data.readableByteCount());
                            });
                        }
    
                        return this.getDelegate().writeWith(messageBody);
                    }));
                }
    
                public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                    return this.writeWith(Flux.from(body).flatMapSequential((p) -> {
                        return p;
                    }));
                }
            };
            return chain.filter(exchange.mutate().response(responseDecorator).build());
        }
    
        public int getOrder() {
            return -2;
        }
    }
    

2.1.2 GlobalFilter 全局过滤器接口,会作用到所有的Route上。

public interface GlobalFilter {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

三、GatewayFilterFactory

在上一篇 Spring Cloud Gateway 源码剖析之Predicate谓词详解 中,已经详细介绍了 PredicateFactory 的各种子类实现。GatewayFilterFactory 也一样,这里就详细分析了哈。

在这里插入图片描述


欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。

在这里插入图片描述
喜欢的话,一键三连走一波。

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
Spring Cloud Gateway 是基于 Spring WebFlux 框架开发的网关组件,提供了一种简单、轻量级的方式来构建微服务架构中的路由和过滤器。 要实现局部过滤器,可以在 Gateway 配置文件中为特定的路由添加过滤器。以下是一种实现方式: 1. 在 Spring Cloud Gateway 配置文件中,定义一个路由规则并指定路由的 ID 和目标 URL,例如: ```yaml spring: cloud: gateway: routes: - id: my_route uri: http://example.com filters: - name: my_filter args: key: value ``` 2. 创建一个自定义的过滤器类,实现 `GatewayFilter` 接口,例如: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.http.HttpStatus; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; public class MyFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 这里可以编写自定义的过滤逻辑 // 例如,根据请求头信息进行验证 String authToken = exchange.getRequest().getHeaders().getFirst("Authorization"); if (authToken == null || !authToken.startsWith("Bearer ")) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 满足条件则继续执行后续过滤器或路由处理器 return chain.filter(exchange); } } ``` 3. 在 Spring Boot 应用程序中,将自定义过滤器注册为一个 Bean,例如: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public MyFilter myFilter() { return new MyFilter(); } } ``` 这样,在配置文件中指定的路由上会应用自定义的过滤器。你可以根据实际需求编写不同的过滤器类来实现各种局部过滤器的逻辑。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老周聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值