序
本文主要研究一下spring cloud gateway的GatewayFilter
GatewayFilter
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/GatewayFilter.java
/**
* 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
*
* Copied from WebFilter
*
* @author Rossen Stoyanchev
* @since 5.0
*/
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<Void>} to indicate when request processing is complete
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
如注释所说,主要用于类似切面的非功能性需求,比如安全、超时控制等。其直接的实现类为OrderedGatewayFilter、ModifyResponseGatewayFilter、GatewayFilterAdapter
OrderedGatewayFilter
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/OrderedGatewayFilter.java
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;
}
public GatewayFilter getDelegate() {
return delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public int getOrder() {
return this.order;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("OrderedGatewayFilter{");
sb.append("delegate=").append(delegate);
sb.append(", order=").append(order);
sb.append('}');
return sb.toString();
}
}
实现了Order接口
ModifyResponseGatewayFilter
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java
public class ModifyResponseGatewayFilter implements GatewayFilter, Ordered {
private final Config config;
public ModifyResponseGatewayFilter(Config config) {
this.config = config;
}
@Override
@SuppressWarnings("unchecked")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
ResolvableType inElementType = ResolvableType.forClass(config.getInClass());
ResolvableType outElementType = ResolvableType.forClass(config.getOutClass());
MediaType contentType = exchange.getResponse().getHeaders().getContentType();
Optional<HttpMessageReader<?>> reader = getHttpMessageReader(codecConfigurer, inElementType, contentType);
Optional<HttpMessageWriter<?>> writer = getHttpMessageWriter(codecConfigurer, outElementType, null);
if (reader.isPresent() && writer.isPresent()) {
ResponseAdapter responseAdapter = new ResponseAdapter(body, getDelegate().getHeaders());
Flux<?> modified = reader.get().read(inElementType, responseAdapter, config.getInHints())
.cast(inElementType.resolve())
.flatMap(originalBody -> Flux.just(config.rewriteFunction.apply(exchange, originalBody)))
.cast(outElementType.resolve());
return getDelegate().writeWith(
writer.get().write((Publisher)modified, outElementType, null, getDelegate(),
config.getOutHints())
);
}
// TODO: error? log?
return getDelegate().writeWith(body);
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body)
.flatMapSequential(p -> p));
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
@Override
public int getOrder() {
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
}
}
主要用于修改response
GatewayFilterAdapter
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/FilteringWebHandler.java
private static class GatewayFilterAdapter implements GatewayFilter {
private final GlobalFilter delegate;
public GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");
sb.append("delegate=").append(delegate);
sb.append('}');
return sb.toString();
}
}
将GlobalFilter转为GatewayFilter的适配器
GatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/GatewayFilterFactory.java
@FunctionalInterface
public interface GatewayFilterFactory<C> extends ShortcutConfigurable, Configurable<C> {
String NAME_KEY = "name";
String VALUE_KEY = "value";
// useful for javadsl
default GatewayFilter apply(Consumer<C> consumer) {
C config = newConfig();
consumer.accept(config);
return apply(config);
}
default Class<C> getConfigClass() {
throw new UnsupportedOperationException("getConfigClass() not implemented");
}
@Override
default C newConfig() {
throw new UnsupportedOperationException("newConfig() not implemented");
}
GatewayFilter apply(C config);
default String name() {
//TODO: deal with proxys
return NameUtils.normalizeFilterFactoryName(getClass());
}
@Deprecated
default ServerHttpRequest.Builder mutate(ServerHttpRequest request) {
return request.mutate();
}
}
spring cloud gateway采用工厂模式来生成GatewayFilter,可以看到这里定义了apply方法,根据config来生成GatewayFilter。GatewayFilterFactory有几个抽象类,分别是AbstractGatewayFilterFactory、AbstractNameValueGatewayFilterFactory(继承了AbstractGatewayFilterFactory
)、AbstractChangeRequestUriGatewayFilterFactory。
AbstractGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/AbstractGatewayFilterFactory.java
public abstract class AbstractGatewayFilterFactory<C>
extends AbstractConfigurable<C> implements GatewayFilterFactory<C> {
@SuppressWarnings("unchecked")
public AbstractGatewayFilterFactory() {
super((Class<C>) Object.class);
}
public AbstractGatewayFilterFactory(Class<C> configClass) {
super(configClass);
}
public static class NameConfig {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
它的直接实现类如下:
- HystrixGatewayFilterFactory
- ModifyRequestBodyGatewayFilterFactory
- ModifyResponseBodyGatewayFilterFactory
- PrefixPathGatewayFilterFactory
- PreserveHostHeaderGatewayFilterFactory
- RedirectToGatewayFilterFactory
- RemoveRequestHeaderGatewayFilterFactory
- RemoveResponseHeaderGatewayFilterFactory
- RequestRateLimiterGatewayFilterFactory
- RetryGatewayFilterFactory
- RewritePathGatewayFilterFactory
- SaveSessionGatewayFilterFactory
- SecureHeadersGatewayFilterFactory
- SetPathGatewayFilterFactory
- SetStatusGatewayFilterFactory
- StripPrefixGatewayFilterFactory
AbstractNameValueGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/AbstractNameValueGatewayFilterFactory.java
public abstract class AbstractNameValueGatewayFilterFactory extends AbstractGatewayFilterFactory<AbstractNameValueGatewayFilterFactory.NameValueConfig> {
public AbstractNameValueGatewayFilterFactory() {
super(NameValueConfig.class);
}
public List<String> shortcutFieldOrder() {
return Arrays.asList(GatewayFilter.NAME_KEY, GatewayFilter.VALUE_KEY);
}
@Validated
public static class NameValueConfig {
@NotEmpty
protected String name;
@NotEmpty
protected String value;
public String getName() {
return name;
}
public NameValueConfig setName(String name) {
this.name = name;
return this;
}
public String getValue() {
return value;
}
public NameValueConfig setValue(String value) {
this.value = value;
return this;
}
@Override
public String toString() {
return new ToStringCreator(this)
.append("name", name)
.append("value", value)
.toString();
}
}
}
将泛型限定为AbstractNameValueGatewayFilterFactory.NameValueConfig,其实现类如下:
- AddRequestHeaderGatewayFilterFactory
- AddRequestParameterGatewayFilterFactory
- AddResponseHeaderGatewayFilterFactory
- SetRequestHeaderGatewayFilterFactory
- SetResponseHeaderGatewayFilterFactory
AbstractChangeRequestUriGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/AbstractChangeRequestUriGatewayFilterFactory.java
/**
* This filter changes the request uri by
* {@link #determineRequestUri(ServerWebExchange, T)} logic.
*
* @author Toshiaki Maki
*/
public abstract class AbstractChangeRequestUriGatewayFilterFactory<T>
extends AbstractGatewayFilterFactory<T> {
private final int order;
public AbstractChangeRequestUriGatewayFilterFactory(Class<T> clazz, int order) {
super(clazz);
this.order = order;
}
public AbstractChangeRequestUriGatewayFilterFactory(Class<T> clazz) {
this(clazz, RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER + 1);
}
protected abstract Optional<URI> determineRequestUri(ServerWebExchange exchange,
T config);
public GatewayFilter apply(T config) {
return new OrderedGatewayFilter((exchange, chain) -> {
Optional<URI> uri = this.determineRequestUri(exchange, config);
uri.ifPresent(u -> {
Map<String, Object> attributes = exchange.getAttributes();
attributes.put(GATEWAY_REQUEST_URL_ATTR, u);
});
return chain.filter(exchange);
}, this.order);
}
}
通过GATEWAY_REQUEST_URL_ATTR设置新的uri,其直接实现类为
- RequestHeaderToRequestUriGatewayFilterFactory(
通过header的值来设定uri
)
GatewayFilterFactory.apply
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java
private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
List<GatewayFilter> 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<String, String> args = definition.getArgs();
if (logger.isDebugEnabled()) {
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(), 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());
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;
}
这里通过factory去实例化每个route的GatewayFilter
小结
spring cloud gateway的GatewayFilter主要是通过GatewayFilterFactory来生产的。而GatewayFilterFactory主要有三个抽象类:
-
AbstractGatewayFilterFactory
- HystrixGatewayFilterFactory
- ModifyRequestBodyGatewayFilterFactory
- ModifyResponseBodyGatewayFilterFactory
- PrefixPathGatewayFilterFactory
- PreserveHostHeaderGatewayFilterFactory
- RedirectToGatewayFilterFactory
- RemoveRequestHeaderGatewayFilterFactory
- RemoveResponseHeaderGatewayFilterFactory
- RequestRateLimiterGatewayFilterFactory
- RetryGatewayFilterFactory
- RewritePathGatewayFilterFactory
- SaveSessionGatewayFilterFactory
- SecureHeadersGatewayFilterFactory
- SetPathGatewayFilterFactory
- SetStatusGatewayFilterFactory
- StripPrefixGatewayFilterFactory
-
AbstractNameValueGatewayFilterFactory(继承了AbstractGatewayFilterFactory)
- AddRequestHeaderGatewayFilterFactory
- AddRequestParameterGatewayFilterFactory
- AddResponseHeaderGatewayFilterFactory
- SetRequestHeaderGatewayFilterFactory
- SetResponseHeaderGatewayFilterFactory
-
AbstractChangeRequestUriGatewayFilterFactory
- RequestHeaderToRequestUriGatewayFilterFactory
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。