在Spring-Cloud-Gateway之请求处理流程中最终网关是将请求交给过滤器链表进行处理。
核心接口:GatewayFilter(网关过滤器),GlobalFilter(全局过滤器),GatewayFilterChain(过滤器链)。
类关联图:
现在流行的微服务,整个项目包含很多个服务,如果没有网关这层,那么我们通过什么方式来限制访问呢?难道在每个服务都建立一套验证,这样代码就看的非常冗余,因此网关的出现解决了这点,只需要在gateway上建立一套验证就可以对整个服务进行使用。感觉有点像计算机网络中的7层协议一样。
Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。
“pre”:请求被执行前调用
“post”:被执行后调用
3.1、GatewayFilter–网关路由过滤器
源码:
/**
* 网关路由过滤器,
* Contract for interception-style, chained processing of Web requests that may
* be used to implement cross-cutting, application-agnostic requirements such
* as security, timeouts, and others. Specific to a Gateway
*
*/
public interface GatewayFilter extends ShortcutConfigurable {
String NAME_KEY = "name";
String VALUE_KEY = "value";
/**
* 过滤器执行方法
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono} to indicate when request processing is complete
*/
Mono filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行。
我们讲解两个实现GatewayFilter的类
3.1.1、OrderedGatewayFilter–排序
源码:
/**
* 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序
*/
public class OrderedGatewayFilter implements GatewayFilter, Ordered {
//目标过滤器
private final GatewayFilter delegate;
//排序字段
private final int order;
public OrderedGatewayFilter(GatewayFilter delegate, int order) {
this.delegate = delegate;
this.order = order;
}
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}
OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类
3.1.2、GatewayFilterAdapter–适配器
源码:
/**
* 全局过滤器的包装类,将全局路由包装成统一的网关过滤器
*/
private static class GatewayFilterAdapter implements GatewayFilter {
/**
* 全局过滤器
*/
private final GlobalFilter delegate;
public GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}
GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类。
3.2、GlobalFilter–全局过滤器
全局过滤器全家桶:
全局过滤器不需要配置只需要添加@component注解就可以加载,并作用域所有路由上!
当然我们也可以通过源码来解读其加载过程:
3.2.1、初始化加载,通过GatewayAutoConfiguration自动创建。
//GatewayAutoConfiguration 类
/**
* 全局过滤器,用户通过HttpClient转发请求
*/
@Bean
public NettyRoutingFilter routingFilter(HttpClient httpClient,
ObjectProvider> headersFilters) {
return new NettyRoutingFilter(httpClient, headersFilters);
}
/**
* 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中
*/
@Bean
public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
}
//GatewayLoadBalancerClientAutoConfiguration 类
/**
* 全局过滤器,用于在通过负载均衡客户端选择服务实例信息
*/
@Bean
@ConditionalOnBean(LoadBalancerClient.class)
public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
return new LoadBalancerClientFilter(client);
}
3.2.2、FilteringWebHandler将GlobalFilter转化成GatewayFilter并生成DefaultGatewayFilterChain(对其进行运行顺序的排序)
//FilteringWebHandler类
/**
* 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
*/
private static List loadFilters(List filters) {
return filters.stream()
.map(filter -> {
//将所有的全局过滤器包装成网关过滤器
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
//判断全局过滤器是否实现了可排序接口
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
//包装成可排序的网关过滤器
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
@Override
public Mono handle(ServerWebExchange exchange) {
//获取请求上下文设置的路由实例
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//获取路由定义下的网关过滤器集合
List gatewayFilters = route.getFilters();
//组合全局的过滤器与路由配置的过滤器
List combined = new ArrayList<>(this.globalFilters);
//添加路由配置过滤器到集合尾部
combined.addAll(gatewayFilters);
//对过滤器进行排序
//TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
logger.debug("Sorted gatewayFilterFactories: "+ combined);
//创建过滤器链表对其进行链式调用
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
3.3、GatewayFilterChain–网关过滤链表
源码:
/**
* 网关过滤链表接口
* 用于过滤器的链式调用
*/
public interface GatewayFilterChain {
/**
* 链表启动调用入口方法*/
Mono filter(ServerWebExchange exchange);
}
实现类:DefaultGatewayFilterChain
/**
* 网关过滤的链表,用于过滤器的链式调用
* 过滤器链表接口的默认实现,
* 包含2个构建函数:
* 1.集合参数构建用于初始化吧构建链表
* 2. index,parent参数用于构建当前执行过滤对应的下次执行的链表
*/
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
/**
* 当前过滤执行过滤器在集合中索引
*/
private final int index;
/**
* 过滤器集合
*/
private final List filters;
public DefaultGatewayFilterChain(List filters) {
this.filters = filters;
this.index = 0;
}
/**
* 构建
* @param parent 上一个执行过滤器对应的FilterChain
* @param index 当前要执行过滤器的索引
*/
private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}
public List getFilters() {
return filters;
}
/**
* @param exchange the current server exchange
* @return
*/
@Override
public Mono filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
//获取当前索引的过滤器
GatewayFilter filter = filters.get(this.index);
//构建当前索引的下一个过滤器的FilterChain
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
//调用过滤器的filter方法执行过滤器
return filter.filter(exchange, chain);
} else {
//当前索引大于等于过滤集合大小,标识所有链表都已执行完毕,返回空
return Mono.empty(); // complete
}
});
}
}
Spring-Cloud-Gateway的过滤器接口分为两种:
GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上。
4.1核心GatewayFilterFactory
通过过滤器定义(FilterDefinition)转换过滤器(GatewayFilter)的部分,在RouteDefinitionRouteLocator类中源码如下:
/**
* 加载过滤器,根据过滤器的定义加载
*/
@SuppressWarnings("unchecked")
private List loadGatewayFilters(String id, List filterDefinitions) {
//遍历过滤器定义,将过滤器定义转换成对应的过滤器
List filters = filterDefinitions.stream()
.map(definition -> {
//通过过滤器定义名称获取过滤器创建工厂
GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());
if (factory == null) {
throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
}
//获取参数
Map args = definition.getArgs();
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
}
//根据args组装配置信息
Map properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
//构建过滤器创建配置信息
Object configuration = factory.newConfig();
ConfigurationUtils.bind(configuration, properties,
factory.shortcutFieldPrefix(), definition.getName(), validator);
//通过过滤器工厂创建GatewayFilter
GatewayFilter gatewayFilter = factory.apply(configuration);
if (this.publisher != null) {
//发布事件
this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
}
return gatewayFilter;
})
.collect(Collectors.toList());
ArrayList ordered = new ArrayList<>(filters.size());
//包装过滤器使其所有过滤器继承Ordered属性,可进行排序
for (int i = 0; i < filters.size(); i++) {
GatewayFilter gatewayFilter = filters.get(i);
if (gatewayFilter instanceof Ordered) {
ordered.add(gatewayFilter);
}
else {
ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
}
}
return ordered;
}
/**
* 获取RouteDefinition中的过滤器集合
*/
private List getFilters(RouteDefinition routeDefinition) {
List filters = new ArrayList<>();
//校验gatewayProperties是否含义默认的过滤器集合
//TODO: support option to apply defaults after route specific filters?
if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
//加载全局配置的默认过滤器集合
filters.addAll(loadGatewayFilters("defaultFilters",
this.gatewayProperties.getDefaultFilters()));
}
if (!routeDefinition.getFilters().isEmpty()) {
//加载路由定义中的过滤器集合
filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
}
//排序
AnnotationAwareOrderComparator.sort(filters);
return filters;
}
/**
*
* 响应header添加数据过滤器
* 用户在response header中添加配置数据
*/
public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
//获取Response并将配置的数据添加到header中
exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
return chain.filter(exchange);
};
}
}。
例如:
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
1AddResponseHeader=X-Response-Default-Foo, Default-Bar 会被解析成FilterDefinition对象 (name =AddResponseHeader ,args= [X-Response-Default-Foo,Default-Bar])
2通FilterDefinition的Name找到AddResponseHeaderGatewayFilterFactory工厂
3通过FilterDefinition 的args 创建Config对象(name=X-Response-Default-Foo,value=Default-Bar)
4通过 AddResponseHeaderGatewayFilterFactory工厂的apply方法传入config创建GatewayFilter对象。
扩展:
Spring中Ordered接口
Spring中提供了一个Ordered接口。Ordered接口,顾名思义,就是用来排序的。Spring是一个大量使用策略设计模式的框架,这意味着有很多相同接口的实现类,那么必定会有优先级的问题。于是,Spring就提供了Ordered这个接口,来处理相同接口实现类的优先级问题。
ordered源码:
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
只有1个方法:getOrder(); 2个变量:最高级(数值最小)和最低级(数值最大)。
order是通过OrderComparator类进行比较的,源码:
public int compare(Object o1, Object o2) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
int i1 = getOrder(o1);
int i2 = getOrder(o2);
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
总结:
OrderComparator比较器进行排序的时候,若2个对象中有一个对象实现了PriorityOrdered接口,那么这个对象的优先级更高。
若2个对象都是PriorityOrdered或Ordered接口的实现类,那么比较Ordered接口的getOrder方法得到order值,值越低,优先级越高。
参考文章:spring cloud gateway-过滤器GatewayFilter、GlobalFilter、GatewayFilterChain、作用、生命周期、GatewayFilterFactory内置过滤器