微服务组件源码6——Spring Gateway

Spring WebFlux 介绍

概述

* Spring WebFlux的定位和SpringMVC一样,不过区别在其处理方法可以使用Flux进行编写,且返回一个发布者Flux/Mono

* Spring WebFlux也可以适配@RequestMapping那一套的编写模式,只不过建议基于Flux来编写controller方法

WebFlux是兼容Spring MVC 基于@Controller,@RequestMapping等注解的编程开发方式的,可以做到平滑切换

WebFluxAutoConfiguration自动配置

* WebFluxAutoConfiguration 自动装配时先自动装配EnableWebFluxConfiguration 而EnableWebFluxConfiguration->DelegatingWebFluxConfiguration ->WebFluxConfigurationSupport。

* WebFluxConfigurationSupport 默认配置:

  • webHandler底层实现:DispatcherHandler

  • 同时配置了其他很多WebFlux核心组件包括 :(这些组件的实现原理和Spring MVC很类似,只不过是基于Flux/Mono形式开发)

映射处理器处理器HandlerMapping和请求适配器HandlerAdapter:优先级为:RouterFunctionMapping、RequestMappingHandlerMapping、SimpleUrlHandlerMapping

异常处理器WebExceptionHandler:WebFluxResponseStatusExceptionHandler

响应处理器HandlerResultHandler : 优先级为:ResponseEntityResultHandler、ServerResponseResultHandler、ResponseBodyResultHandler、ViewResolutionResultHandler

@Configuration**//** 条件装配 只有启动的类型是 REACTIVE 时加载
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)// 只有存在 WebFluxConfigurer 实例 时加载
@ConditionalOnClass(WebFluxConfigurer.class )// 在不存在 WebFluxConfigurationSupport 实例时 加载
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })// 在之后装
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class ,
CodecsAutoConfiguration.class , ValidationAutoConfiguration.class })// 自动装配顺序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {
@Configuration
@EnableConfigurationProperties({ResourceProperties.class , WebFluxProperties.class })
// 接口编程 在装配 WebFluxConfig 之前要先 装配 EnableWebFluxConfiguration
@Import({EnableWebFluxConfiguration.class })
public static class WebFluxConfig implements WebFluxConfigurer {
// 隐藏部分源码 /** * Configuration equivalent to {@code @EnableWebFlux}. */
}

@Configuration
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
// 隐藏部分代码

public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
this .webFluxProperties = webFluxProperties;
this .webFluxRegistrations = webFluxRegistrations.getIfUnique();
}

// 实现类 DelegatingWebFluxConfiguration 的创建 RequestMappingHandlerAdapter RequestMappingHandlerMapping 的方法
// 优先从容器里的 WebFluxRegistrations 来获取
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this .webFluxRegistrations != null
&& this .webFluxRegistrations.getRequestMappingHandlerAdapter() != null ) {
return this .webFluxRegistrations.getRequestMappingHandlerAdapter();
}
// 默认为支持 @RequestMapping 注解的 RequestMappingHandlerAdapter();
return super .createRequestMappingHandlerAdapter();
}

@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if (this .webFluxRegistrations != null
&& this .webFluxRegistrations.getRequestMappingHandlerMapping() != null ) {
return this .webFluxRegistrations.getRequestMappingHandlerMapping();
}
// 默认为支持 @RequestMapping 注解的 RequestMappingHandlerMapping();
return super .createRequestMappingHandlerMapping();
}
}

@Configuration
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
// 隐藏部分代码
//
}

private static class ResourceChainResourceHandlerRegistrationCustomizer
implements ResourceHandlerRegistrationCustomizer {
// 隐藏部分代码
}

}

public class WebFluxConfigurationSupport implements ApplicationContextAware {

@Nullable
private Map<String, CorsConfiguration> corsConfigurations ;
@Nullable
private PathMatchConfigurer pathMatchConfigurer ;
@Nullable
private ViewResolverRegistry viewResolverRegistry ;
@Nullable
private ApplicationContext applicationContext ;
@Nullable
public final ApplicationContext getApplicationContext() {
return this .applicationContext ;
}

@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this .applicationContext = applicationContext;
}
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}

@Bean
@Order(0)
public WebExceptionHandler responseStatusExceptionHandler() {
return new WebFluxResponseStatusExceptionHandler();
}

// 默认为 RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("webFluxContentTypeResolver" ) RequestedContentTypeResolver contentTypeResolver) {

RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setContentTypeResolver(contentTypeResolver);
mapping.setCorsConfigurations(getCorsConfigurations());

PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null ) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useCaseSensitiveMatch != null ) {
mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null ) {
mapping.setPathPrefixes(pathPrefixes);
}

return mapping;
}

protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}

@Bean
public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageReaders(serverCodecConfigurer.getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());

return mapping;
}

protected RouterFunctionMapping createRouterFunctionMapping() {
return new RouterFunctionMapping();
}

@Bean
public HandlerMapping resourceHandlerMapping(ResourceUrlProvider resourceUrlProvider) {
ResourceLoader resourceLoader = this .applicationContext ;
if (resourceLoader == null ) {
resourceLoader = new DefaultResourceLoader();
}
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
registry.setResourceUrlProvider(resourceUrlProvider);
addResourceHandlers(registry);

AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
if (handlerMapping != null ) {
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useTrailingSlashMatch != null ) {
handlerMapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (useCaseSensitiveMatch != null ) {
handlerMapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
}
else {
handlerMapping = new org.springframework.web.reactive.config.WebFluxConfigurationSupport.EmptyHandlerMapping();
}
return handlerMapping;
}

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("webFluxAdapterRegistry" ) ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxConversionService" ) FormattingConversionService conversionService,
@Qualifier("webFluxValidator" ) Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setMessageReaders(serverCodecConfigurer.getReaders());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
adapter.setReactiveAdapterRegistry(reactiveAdapterRegistry);

ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
configureArgumentResolvers(configurer);
adapter.setArgumentResolverConfigurer(configurer);

return adapter;
}

protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
return new RequestMappingHandlerAdapter();
}

@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return new HandlerFunctionAdapter();
}

@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return new SimpleHandlerAdapter();
}

@Bean
public ResponseEntityResultHandler responseEntityResultHandler(
@Qualifier("webFluxAdapterRegistry" ) ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxContentTypeResolver" ) RequestedContentTypeResolver contentTypeResolver) {
return new ResponseEntityResultHandler(serverCodecConfigurer.getWriters(),
contentTypeResolver, reactiveAdapterRegistry);
}

@Bean
public ResponseBodyResultHandler responseBodyResultHandler(
@Qualifier("webFluxAdapterRegistry" ) ReactiveAdapterRegistry reactiveAdapterRegistry,
ServerCodecConfigurer serverCodecConfigurer,
@Qualifier("webFluxContentTypeResolver" ) RequestedContentTypeResolver contentTypeResolver) {
return new ResponseBodyResultHandler(serverCodecConfigurer.getWriters(),
contentTypeResolver, reactiveAdapterRegistry);
}

@Bean
public ViewResolutionResultHandler viewResolutionResultHandler(
@Qualifier("webFluxAdapterRegistry" ) ReactiveAdapterRegistry reactiveAdapterRegistry,
@Qualifier("webFluxContentTypeResolver" ) RequestedContentTypeResolver contentTypeResolver) {
ViewResolverRegistry registry = getViewResolverRegistry();
List<ViewResolver> resolvers = registry.getViewResolvers();
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(
resolvers, contentTypeResolver, reactiveAdapterRegistry);
handler.setDefaultViews(registry.getDefaultViews());
handler.setOrder(registry.getOrder());
return handler;
}

@Bean
public ServerResponseResultHandler serverResponseResultHandler(
ServerCodecConfigurer serverCodecConfigurer) {
List<ViewResolver> resolvers = getViewResolverRegistry().getViewResolvers();
ServerResponseResultHandler handler = new ServerResponseResultHandler();
handler.setMessageWriters(serverCodecConfigurer.getWriters());
handler.setViewResolvers(resolvers);
return handler;
}

private static final class EmptyHandlerMapping extends AbstractHandlerMapping {

@Override
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
return Mono.empty ();
}
}

}

HTTPHandler

不同http服务器调用适配

* 使用一个简单的处理业务请求和响应的抽象,用来适配不同HTTP服务容器的API。

不同的HTTP服务容器在处理请求时需要调用此HTTPHandler,从而都会走到此HTTPHandler对象中

* 在HttpHandlerAutoConfiguration配置默认为HttpWebHandlerAdapter,里面装饰了一系列的WebHandler,以及实现Mono<Void> handle方法定义了请求响应的整个流程

* 例如在SpringBoot中使用ReactiveWebServerApplicationContext作用应用上下文。那么在容器刷新的时候会启动web服务,此时会基于不用的工厂创建不同的服务

//WebFlux 核心组件又是什么时候注入到对应的容器上下文中的呢?其实是在刷新容器上下文时注入进去的。
public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext implements ConfigurableWebServerApplicationContext {

@Override
protected void onRefresh() {
super .onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start reactive web server" , ex);
}
}
private void createWebServer() {
WebServerManager serverManager = this .serverManager;
if (serverManager == null ) {
String webServerFactoryBeanName = getWebServerFactoryBeanName();
ReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);
boolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();
// 这里创建容器管理时注入 httpHandler
this .serverManager = new WebServerManager(this , webServerFactory, this ::getHttpHandler, lazyInit);
getBeanFactory().registerSingleton("webServerGracefulShutdown" ,
new WebServerGracefulShutdownLifecycle(this .serverManager));
// 注册一个 web 容器启动服务类 , 该类继承了 SmartLifecycle
getBeanFactory().registerSingleton("webServerStartStop" ,
new WebServerStartStopLifecycle(this .serverManager));
}
initPropertySources();
}
protected HttpHandler getHttpHandler() {
String\[\] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class );
if (beanNames.length == 0) {
throw new ApplicationContextException(;
}
if (beanNames.length > 1) {
throw new ApplicationContextException();
}
// 容器上下文获取 httpHandler
return getBeanFactory().getBean(beanNames0, HttpHandler.class );
}

}

* 例如NettyReactiveWebServerFactory工厂会创建Netty服务器,在其中的NettyServer里名就关联ReactorHttpHandlerAdapte(HttpWebHandlerAdapter)

SpringBoot提供的内嵌的NettyWebServer服务,基于NIO的模式,在请求到达的时候,就会让工作线程调用此ReactorHttpHandlerAdapte的apply方法

ReactorHttpHandlerAdapte的apply方法就是执行this.HttpWebHandlerAdapter.handle(request, response),会使用DispachHander处理解析请求,定义好整个处理流程的Mono

接着Netty会直接订阅此Mono,触发整个流程

HttpWebHandlerAdapter 实现类

* 在HttpHandlerAutoConfiguration配置里默认为HttpWebHandlerAdapter,里面装饰了一系列的WebHandler,以及实现Mono<Void> handle方法定义了请求响应的整个流程

  • 在构建者Builder中会先收集好DispatcherHandler、FilteringWebHandler、WebExceptionHandler等信息,再进行builder

  • 实现了HttpHandler接口的的handel方法

①创建ServerWebExchange,底层主要保存了 ServerHttpRequest request和 ServerHttpResponse response对象

②调用委托的装饰器处理类ExceptionHandlingWebHandler -> FilteringWebHandler -> DispatcherHandler 的handle方法 ---具体流程见下

  • 如果最终发生异常,内部异常或者客户端连接异常返回Mono.empty(),其他返回Mono.error(ex);

  • 如果调用没有异常,那么会执行response::setComplete做一些钩子方法的回调

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this .forwardedHeaderTransformer != null ) {
request = this .forwardedHeaderTransformer.apply(request);
}
// 创建 ServerWebExchange ,底层主要保存了 ServerHttpRequest request ServerHttpResponse response 对象
ServerWebExchange exchange = createExchange(request, response);
// 核心流程:
//1 、调用委托的装饰器处理类 ExceptionHandlingWebHandler -> FilteringWebHandler -> DispatcherHandler handle 方法
//2 、如果最终发生异常,内部异常或者客户端连接异常返回 Mono.empty() ,其他返回 Mono.error(ex);
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer (response::setComplete));
}

HttpHandlerAutoConfiguration自动配置HttpWebHandlerAdapter

* 其中从容器获取的WebHandler就是DispatcherHandler

WebHandler

WebHandler 接口

* 一个用于处理业务请求抽象接口,定义了一系列处理行为

  • 其中HTTPHandler实现类HttpWebHandlerAdapter也实现这个接口,底层依序装饰如下图的WebHandler

  • 核心方法Mono<Void> handle(ServerWebExchange exchange);对请求进行处理,并返回一个Mono<Void>(基于Flux模式的开发)

public interface WebHandler {
Mono<Void> handle(ServerWebExchange exchange);
}

*相关核心实现类如下

DispatcherHandler

请求处理的总控制器,实际工作是由多个可配置的组件来处理。

请求分发处理器,Spring WebFlux 的访问入口。和 Spring MVC 的 DispatcherServlet 类似,主要流程如下

* 从容器中获取再排序List<HandlerMapping> handlerMappings、List<HandlerAdapter> handlerAdapters;、List<HandlerResultHandler> resultHandlers; 在自动配置类中默认的类型为

映射处理器处理器HandlerMapping和请求适配器HandlerAdapter:优先级为:RouterFunctionMapping、RequestMappingHandlerMapping、SimpleUrlHandlerMapping

* Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange))

遍历handlerMappings中收集到所有HandlerMapping实现类,调用其getHandler组装成新的Mono<Object>,在getHandler会定位到处理器

* flatMap(handler -> invokeHandler(exchange, handler))

对上一步返回的Mono<Object>,调用对应HandlerAdapter进行请求处理,返回Mono<HandlerResult>

使用handlerAdapter.supports(handler),为true就return handlerAdapter.handle(exchange, handler);

* flatMap(result -> handleResult(exchange, result));

对上一步返回的Mono<HandlerResult>调用对应HandlerResultHandler 进行结果处理

使用resultHandler.supports(handlerResult),为true就调用其handleResult(exchange, result)

public class DispatcherHandler implements WebHandler, ApplicationContextAware {

@Nullable
private List<HandlerMapping> handlerMappings ;
@Nullable
private List<HandlerAdapter> handlerAdapters ;
@Nullable
private List<HandlerResultHandler> resultHandlers ;

public DispatcherHandler() {}
public DispatcherHandler(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
// 从容器中获取在排序
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors (
context, HandlerMapping.class , true , false );
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort (mappings);
this .handlerMappings = ...;
this .resultHandlers = ...;
}

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this .handlerMappings == null ) {
//Mono.error(ex);
return createNotFoundError();
}
// 遍历 一个执行 handlerMappings 中收集到 HandlerMapping 实现类,调用其 getHandler 组装成新的 Flux
return Flux.fromIterable (this .handlerMappings )
.concatMap(mapping -> mapping.getHandler(exchange))
// 一个元素执行的结果
.next()
.switchIfEmpty(createNotFoundError())
// 再调用对应HandlerAdapter进行处理
.flatMap(handler -> invokeHandler(exchange, handler))
// 再调用对应HandlerResultHandler 进行处理
.flatMap(result -> handleResult(exchange, result));
}

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this .handlerAdapters != null ) {
for (HandlerAdapter handlerAdapter : this .handlerAdapters ) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error (new IllegalStateException("No HandlerAdapter: " + handler));
}

private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.checkpoint("Handler " + result.getHandler() + " DispatcherHandler" )
.onErrorResume(ex ->
result.applyExceptionHandler(ex).flatMap(exResult -> {
String text = "Exception handler " + exResult.getHandler() +
", error= \" " + ex.getMessage() + " \" DispatcherHandler" ;
return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
}));
}

private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this .resultHandlers != null ) {
for (HandlerResultHandler resultHandler : this .resultHandlers ) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}

}

FilteringWebHandler

* 底层封装了DispatcherHandler和拦截器

  • 拦截器使用责任链模式,支持对DispatcherHandler进行前置后置的拦截

public class FilteringWebHandler extends WebHandlerDecorator {

private final DefaultWebFilterChain chain ;

public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super (handler);
//handler 表示 DispatcherHandler filters 连接器集合
// 每一个拦截器都会生成一个 DefaultWebFilterChain ,各个拦截器使用变量 chain 串联起来
//while (iterator.hasPrevious()) {
// chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
// }
this .chain = new DefaultWebFilterChain(handler, filters);
}

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
// 返回拦截器链头结点的 filter 方法:如果存在链表可用,依序递归执行 filter ,否调用 DispatcherHandler handle
// 在每一个具体的拦截器中,会自己具体是前置处理还是后置处理,是放行还是中断
// 返回: Mono.defer(() ->
// this.currentFilter != null && this.chain != null ?
// current.filter(exchange, chain):
// this.handler.handle(exchange));
return this .chain .filter(exchange);
}

}

//DefaultWebFilterChain 责任链设计:递归 + 拦截链表 + 在每一个具体的拦截器中,会自己具体是前置处理还是后置处理,是放行还是中断

@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer (() ->
this .currentFilter != null && this .chain != null ?
invokeFilter(this .currentFilter , this .chain , exchange) :
this .handler .handle(exchange));
}

ExceptionHandlingWebHandler

* 先执行FilteringWebHandler的流程

* 在使用onErrorResume转换操作方法进封装为异常处理器发布者

  • onErrorResume也是一个转换操作符,当发生异常时,会丢弃前面的流程,直接转为订阅到onErrorResume里指定的发布者

意味着当上链发生异常时,使用指定的exceptionHandlers一个一个处理,如果前面一个处理器接着抛出异常,那么就由第二个来处理。直到有一个成功执行就作为结果

public class ExceptionHandlingWebHandler extends WebHandlerDecorator {

private final List<WebExceptionHandler> exceptionHandlers ;

public ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers) {

super (delegate);

List<WebExceptionHandler> handlersToUse = new ArrayList<>();

handlersToUse.add(new org.springframework.web.server.handler.ExceptionHandlingWebHandler.CheckpointInsertingHandler());

handlersToUse.addAll(handlers);

this .exceptionHandlers = Collections.unmodifiableList (handlersToUse);

}

@Override

public Mono<Void> handle(ServerWebExchange exchange) {

Mono<Void> completion;

// 先执行 FilteringWebHandler 的流程

try {

completion = super .handle(exchange);

} catch (Throwable ex) {

completion = Mono.error (ex);

}

// 在使用 onErrorResume 包装异常处理器

//onErrorResume 也是一个转换操作符,当发生异常时,会丢弃前面的流程,直接转为订阅到 onErrorResume 里指定的发布者

// 下面的流就是:使用指定的 exceptionHandlers 依序一个一个处理异常,如果前面一个处理器接着抛出异常,那么就由第二个来处理

// 否则,异常处理的结果就会作为最终的处理结果发布者

for (WebExceptionHandler handler : this .exceptionHandlers ) {

completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));

}

return completion;

}

}

SpringCloud gateway整体流程

流程图

* 基于Spring webFlux的请求处理框架,DispatcherHandler首先会接受请求

  • 使用内部注册的HandlerMappinp集合来匹配请求,这里优先选择RoutePredicateHandlerMapping来获取Object Handler处理器

  • SimpleHandlerAdapter会适配处理到此将请求,直接调用Object Handler(FilteringWebHandler)处理器的handel方法,里面会使用predicate进行匹配到Route

* 此FilteringWebHandler包含指定的Route,其内也包含了内置和用户指定的Fliter

其中LoadBalancerClientFilter只用于把请求url进行负载均衡找出目标机器,在使用内部的httpClient发起远处调用

* 底层的http服务功能丰富,一般使用netty,因为netty的NIO支持和Flux的响应式编程适配得不错

RoutePredicateHandlerMapping

* SpringFlux中DispatchHandler处理请求的流程,这里就会优先使用RoutePredicateHandlerMapping,调用其getHandler->getHandlerInternal

Flux.fromIterable (this .handlerMappings )

.concatMap(mapping -> mapping.getHandler(exchange))

.next()

.switchIfEmpty(createNotFoundError())

.flatMap(handler -> invokeHandler(exchange, handler))

.flatMap(result -> handleResult(exchange, result));

* 父类AbstractHandlerMapping主要作用是调用子类的getHandlerInternal

public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {

//略

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {equest request = exchange.getRequest();
//略

return handler;
});
}

* RoutePredicateHandlerMapping 作用

①从其成员CachingRouteLocator中获取所有的Flux<Route>,遍历每一个Route。获取并执行PredicategetPredicate().apply(exchange)

②把第一个匹配成功的Route,存于请求属性中gatewayRoute -> Route,

③把RoutePredicateHandlerMapping中的FilteringWebHandler成员作为返回结果

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler ;
private final RouteLocator routeLocator ;
private final Integer managementPort ;
private final RoutePredicateHandlerMapping.ManagementPortType managementPortType ;

public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
this .webHandler = webHandler;
this .routeLocator = routeLocator;
this .managementPort = getPortProperty(environment, "management.server." );
this .managementPortType = this .getManagementPortType(environment);
this .setOrder(1);
this .setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
}

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// 如果 managementPort 管理端口,返回空
if (this .managementPortType == RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT && this .managementPort != null && exchange.getRequest().getURI().getPort() == this .managementPort ) {
return Mono.empty ();
} else {
// 调用 lookupRoute ,指定断言 Predicate 获取第一个匹配的 Routes
// 存于请求属性中 gatewayRoute -> Route, 返回 RoutePredicateHandlerMapping 中的 FilteringWebHandler 作为返回结果
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR , this .getSimpleName());
return this .lookupRoute(exchange).flatMap((r) -> {
exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR );
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR , r);
return Mono.just (this .webHandler );
}).switchIfEmpty(Mono.empty ().then(Mono.fromRunnable (() -> {
exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR );
})));
}
}
// 从其成员 CachingRouteLocator 中获取所有的 Flux<Route> ,遍历每一个 Route 。获取并执行 PredicategetPredicate().apply(exchange)
// 取第一个匹配成功的 Route
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this .routeLocator .getRoutes().concatMap((route) -> {
return Mono.just (route).filterWhen((r) -> {
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR , r.getId());
return (Publisher)r.getPredicate().apply(exchange);
}).onErrorResume((e) -> {
return Mono.empty ();
});
}).next().map((route) -> {
this .validateRoute(route, exchange);
return route;
});
}

//...
}

FilteringWebHandler

* SpringFlux的处理器适配器SimpleHandlerAdapter会调用FilteringWebHandler的handle方法

* FilteringWebHandler的handle从请求属性中gatewayRoute获取route,获取其getFilters()全部配置的过滤器和全局过滤器,排序,在组装成DefaultGatewayFilterChain

* 过滤器链的底层List<GatewayFilter> filters作为链表,index表示当前执行的过滤器,

每一个具体的过滤器内会会调用DefaultGatewayFilterChain.filter,这样形成了递归调用,使得过滤器链的前后执行顺序是相反的

public class FilteringWebHandler implements WebHandler {

protected static final Log logger = LogFactory.getLog (FilteringWebHandler.class );

private final List<GatewayFilter> globalFilters ;

// 对传递进来的全局过滤器进行 Order 排序
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this .globalFilters = loadFilters (globalFilters);
}
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
// 为一些没有实现 filter(ServerWebExchange exchange, GatewayFilterChain chain) GlobalFilter 进行适配一写
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList ());
}

//FilteringWebHandler handle 从请求属性中 gatewayRoute 获取 route ,获取其 getFilters() 全部配置的过滤器和全局过滤器,排序,在组装成 DefaultGatewayFilterChain
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR );
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList<>(this .globalFilters );
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort (combined);
return new DefaultGatewayFilterChain(combined).filter(exchange);
}

// 过滤器链
// 底层 List<GatewayFilter> filters 作为链表, index 表示当前执行的过滤器,
//每一个 具体的过滤器内会会调用 DefaultGatewayFilterChain.filter ,这样形成了递归调用,使得过滤器链的前后执行顺序是相反的
private static class DefaultGatewayFilterChain implements GatewayFilterChain {

private final int index ;

private final List<GatewayFilter> filters ;

DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this .filters = filters;
this .index = 0;
}

private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this .filters = parent.getFilters();
this .index = index;
}

public List<GatewayFilter> getFilters() {
return filters ;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer (() -> {
if (this .index < filters .size()) {
GatewayFilter filter = filters .get(this .index );
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this ,
this .index + 1);
return filter.filter(exchange, chain);
}
else {
return Mono.empty (); // complete
}
});
}

}

private static class GatewayFilterAdapter implements GatewayFilter {

private final GlobalFilter delegate ;

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();
}

}

}

Gateway 自动配置

自动配置类中可以看到Gateway的初始化过程

在 org.springframework.cloud.gateway.config 包下,我们可以看到四个配置类 :

* GatewayAutoConfiguration

* GatewayClassPathWarningAutoConfiguration

* GatewayLoadBalancerClientAutoConfiguration

* GatewayRedisAutoConfiguration

GatewayClassPathWarningAutoConfiguration

Spring Cloud Gateway 2.x 基于 Spring WebFlux 实现。

GatewayClassPathWarningAutoConfiguration用于检查项目是否正确导入 spring-boot-starter-webflux 依赖,而不是错误导入 spring-boot-starter-web 依赖。

@Configuration(proxyBeanMethods = false )
@AutoConfigureBefore(GatewayAutoConfiguration.class )
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled" , matchIfMissing = true )
public class GatewayClassPathWarningAutoConfiguration {

private static final Log log = LogFactory
.getLog (GatewayClassPathWarningAutoConfiguration.class );

private static final String BORDER = " \n\n ********************************************************** \n\n " ;

@Configuration(proxyBeanMethods = false )
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet" )
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET )
protected static class SpringMvcFoundOnClasspathConfiguration {

public SpringMvcFoundOnClasspathConfiguration() {
throw new MvcFoundOnClasspathException();
}

}

@Configuration(proxyBeanMethods = false )
@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler" )
protected static class WebfluxMissingFromClasspathConfiguration {

public WebfluxMissingFromClasspathConfiguration() {
log .warn(BORDER + "Spring Webflux is missing from the classpath, "

  • "which is required for Spring Cloud Gateway at this time. "
  • "Please add spring-boot-starter-webflux dependency." + BORDER );
    }

}

}

GatewayLoadBalancerClientAutoConfiguration

* 初始化 LoadBalancerClientFilter过滤器,拦截请求进行负载均衡和服务发现

主要这时gateway自己定义的过滤器,不是Spring Flux的过滤器

* 需要从容器中获取LoadBalancerClient,例如RibbonLoadBalancerClient实现类

@Configuration(proxyBeanMethods = false )
@ConditionalOnClass({ LoadBalancerClient.class , RibbonAutoConfiguration.class ,
DispatcherHandler.class })
@AutoConfigureAfter(RibbonAutoConfiguration.class )
@EnableConfigurationProperties(LoadBalancerProperties.class )
public class GatewayLoadBalancerClientAutoConfiguration {

@Bean
@ConditionalOnBean(LoadBalancerClient.class )
@ConditionalOnMissingBean({ LoadBalancerClientFilter.class ,
ReactiveLoadBalancerClientFilter.class })
@ConditionalOnEnabledGlobalFilter
public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
LoadBalancerProperties properties) {
return new LoadBalancerClientFilter(client, properties);
}

}

GatewayRedisAutoConfiguration

GatewayRedisAutoConfiguration ,初始化 RedisRateLimiter 。

RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 实现网关的限流功能

GatewayAutoConfiguration (核心)

GatewayAutoConfiguration ,Spring Cloud Gateway 核心配置类,初始化如下的组件

NettyConfiguration

GlobalFilter

FilteringWebHandler

GatewayProperties

PrefixPathGatewayFilterFactory

RoutePredicateFactory

RouteDefinitionLocator

RouteLocator

RoutePredicateHandlerMapping

GatewayWebfluxEndpoint

* NettyConfiguration

①创建一个类型为 java.util.Objects.Consumer 的 Bean 对象。

该 Consumer 会将传入类型为 reactor.ipc.netty.options.HttpClientOptions.Builder 的参数 opts ,设置 opts 的 poolResources 属性。

调用 PoolResources.elastic("proxy")方法,创建name属性为 "proxy" 的reactor.ipc.netty.resources.PoolResources 。其中"proxy" 用于实际使用时,打印日志的标记。

②创建一个类型为HttpClient的Bean对象。该HttpClient使用Netty实现的Client 。

③创建一个类型为NettyRoutingFilter(HttpClient ②Bean)的Bean对象。

④创建一个类型为NettyWriteResponseFilter的Bean对象。

⑤创建一个类型为ReactorNettyWebSocketClient的Bean对象,用于下文 WebsocketRoutingFilter的Bean对象创建。

* GlobalFilter

①创建一个类型为RouteToRequestUrlFilter的Bean对象。

②创建一个类型为ForwardRoutingFilter的Bean对象

③创建一个类型为WebSocketService的Bean对象。

④创建一个类型为WebsocketRoutingFilter的Bean对象。

* FilteringWebHandler

  • 当所有GlobalFilter 初始化完成时( 包括上面的 NettyRoutingFilter / NettyWriteResponseFilter ),创建一个类型为FilteringWebHandler(List<GlobalFilter> globalFilters) 的Bean对象

  • 注意这时RoutePredicateHandlerMapping对象需要用到的FilteringWebHandler。和SpringFlux自己的FilteringWebHandler不一样

* GatewayProperties

创建一个类型为GatewayProperties 的Bean对象,用于加载配置文件配置的 RouteDefinition / FilterDefinition 。

* xxxFilterFactory

创建org.springframework.cloud.gateway.filter.factory 包下的 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 接口的实现们

这些都是内置的过滤器

* xxxRoutePredicateFactory

创建org.springframework.cloud.gateway.handler.predicate 包下的 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 接口的实现们。

这些都是内置的predicate

* RouteDefinitionLocator

①创建一个RouteDefinitionLocator接口类型的PropertiesRouteDefinitionLocator(GatewayProperties Bean) 的Bean对象。

②创建一个类型为InMemoryRouteDefinitionRepository 的Bean对象。

③创建一个类型为CompositeRouteDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators①+②)的Bean对象。--@Primary

④基于DiscoveryClient注册发现的RouteDefinitionLocator实现类,需要手动引入配置,

* RouteLocator

①创建一个类型为RouteDefinitionRouteLocator的Bean对象

②创建一个类型为CachingRouteLocator(List<RouteLocator> routeLocators) 的Bean对象。该 Bean 对象内嵌 CompositeRouteLocator 对象。 --@Primary

* RoutePredicateHandlerMapping

  • 创建一个类型为RoutePredicateHandlerMapping(FilteringWebHandler webHandler,RouteLocator routeLocator)的Bean对象,用于查找匹配到 Route ,并进行处理

  • 是Spring webFlux需要的HandlerMapping接口实现类,其功能和SpringMVC中的一样,用于把一个请求映射为一个处理器。进行请求处理

其order为1,优先级位于RouterFunctionMapping之后

* GatewayWebfluxEndpoint

创建一个类型为 org.springframework.cloud.gateway.actuate.GatewayWebfluxEndpoint 的 Bean 对象,提供管理网关的 HTTP API

Route路由

整体流程

* RouteDefinitionLocator接口负责读取路由的配置,并生成配置RouteDefinition 集合发布者Flux<RouteDefinition> ,RouteDefinitionLocator 接口有四种实现 :

①PropertiesRouteDefinitionLocator,从配置文件( 例如,YML / Properties 等 ) 读取。

②RouteDefinitionRepository,从存储器(例如,内存 / Redis / MySQL 等 )读取。

③DiscoveryClientRouteDefinitionLocator ,从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取。

④CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* RouteLocator接口负责生成路由的最终实体类Route,有如下几种方法

①通过 RouteDefinitionRouteLocator获取上一步的RouteDefinition,并转换成 Route 。

有多个实现类CompositeRouteLocator / CachingRouteLocator ,最重要的是RouteDefinitionRouteLocator

②可以通过代码定义自定义路由

public RouteLocator customRouteLocator() {
return Routes.locator()
.route("test" )
.predicate(host("**.abc.org" ).and(path("/image/png" )))
.addResponseHeader("X-TestHeader" , "foobar" )
.uri("http://httpbin.org:80" )
.build();
}

RouteDefinitionLocator

概述

* RouteDefinitionLocator接口

负责读取路由的配置,并生成配置RouteDefinition 集合Flux<RouteDefinition> ,RouteDefinitionLocator 接口有四种实现 :

①PropertiesRouteDefinitionLocator,从配置文件( 例如,YML / Properties 等 ) 读取。

②RouteDefinitionRepository,从存储器(例如,内存 / Redis / MySQL 等 )读取。

③DiscoveryClientRouteDefinitionLocator ,从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取。

④CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* 接口只有一个方法getRouteDefinitions以获取Flux<RouteDefinition>

public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}

PropertiesRouteDefinitionLocator

* 从配置文件( 例如,YML / Properties 等 ) 读取路由配置

* 基于GatewayProperties,调用其getRoutes获取Flux<RouteDefinition>集合,Flux.fromIterable(this.properties.getRoutes());

* GatewayProperties借助@ConfigurationProperties("spring.cloud.gateway"),

①已经会配置文件的值映射到List<RouteDefinition> routes中

private List<RouteDefinition> routes = new ArrayList<>();

②添加一个默认的RemoveNonProxyHeadersGatewayFilterFactory到List<FilterDefinition>defaultFilters 默认富过滤器属性中

//GatewayAutoConfiguration

@Bean

@ConditionalOnMissingBean

public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(

GatewayProperties properties) {

return new PropertiesRouteDefinitionLocator(properties);

}

public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

private final GatewayProperties properties ;

public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
this .properties = properties;
}

@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(this .properties .getRoutes());
}
}

@ConfigurationProperties("spring.cloud.gateway" )
@Validated
public class GatewayProperties {

//ConfigurationProperties 注解的作用已经会配置文件的值映射到此 routes
@NotNull
@Valid
private List<RouteDefinition> routes = new ArrayList<>();

// 添加一个默认的 List<FilterDefinition> 定义
private List<FilterDefinition> defaultFilters = loadDefaults();
private ArrayList<FilterDefinition> loadDefaults() {
ArrayList<FilterDefinition> defaults = new ArrayList<>();
FilterDefinition definition = new FilterDefinition();
definition.setName(normalizeFilterName(RemoveNonProxyHeadersGatewayFilterFactory.class ));
defaults.add(definition);
return defaults;
}

//
}

* 配置文件举例

spring:

cloud:

gateway:

routes:

  • id: payment_routh #payment_routh

uri: lb://cloud-provider-service #匹配后提供服务的路由地址,lb后跟提供服务的微服务的名

predicates:

  • Path=/payment/get/** #断言,路径(是除了host之外的路径串)相匹配的进行路由,即把uri作为目标地址,

filters:

  • AddRequestParameter=foo, bar #对匹配的请求,会额外添加foo=bar的请求参数。

  • AddResponseHeader=X-Response-Foo, Bar #对匹配的请求,响应返回时会额外添加X-Response-Foo:Bar的header返回。

#如果存在=对,第一个会作为name,其他存于map中

spring:

cloud:

gateway:

routes:

  • id: rewritepath_route

uri: lb://foo-server

predicates:

  • Path=/foo/**

filters:

  • RewritePath=/foo/(?<segment>.*), /$\{segment}

对于上面的例子,如果请求的路径是/foo/bar,则gateway会将请求路径改为/bar,在拼接到uri为lb://foo-server/bar

这个例子是常用的,如上foo是用于到此route,最终从服务列表中获取对应的最终ip+端口

DiscoveryClientRouteDefinitionLocator

通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组

* 获取对应的服务发现客户端,即注册中心的客户端对象DiscoveryClient

* 确定路由id的前缀routeIdPrefix,这里默认为DiscoveryClient 类名

* 遍历服务列表,处理每一个服务,生成Flux<RouteDefinition>

①设置 ID = routeIdPrefix_serviceId

②设置 URI = lb://serviceId

③添加 Path 匹配断言: -Path = /serviceId/**

④添加 Path 重写过滤器:- RewritePath=/serviceId/(?<segment>.*), /$\{segment}

public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
private final DiscoveryClient discoveryClient ;
private final String routeIdPrefix ;
public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
this .discoveryClient = discoveryClient;
this .routeIdPrefix = this .discoveryClient .getClass().getSimpleName() + "_" ;
}

@Override
public Flux<RouteDefinition> getRouteDefinitions() {
// 遍历服务列表,处理每一个服务
return Flux.fromIterable(discoveryClient .getServices())
.map(serviceId -> {
RouteDefinition routeDefinition = new RouteDefinition();
// 设置 ID = routeIdPrefix_serviceId
routeDefinition.setId(this .routeIdPrefix + serviceId);
// 设置 URI = lb://serviceId
routeDefinition.setUri(URI.create("lb://" + serviceId));

// 添加 Path 匹配断言: -Path = /serviceId/**
PredicateDefinition subPredicate = new PredicateDefinition();
subPredicate.setName(normalizePredicateName(PathRoutePredicateFactory.class ));
subPredicate.addArg(PATTERN_KEY, "/" + serviceId + "/**" );
routeDefinition.getPredicates().add(subPredicate);

// 添加 Path 重写过滤器
// 添加过滤器: - - RewritePath=/serviceId/(?<segment>.*), /\\{segment}** FilterDefinition filter = ****new**** FilterDefinition(); filter.setName(normalizeFilterName(RewritePathGatewayFilterFactory.****class**** )); String regex = ****"/"**** + serviceId + ****"/(?\.\*)"**** ; String replacement = ****"/{remaining}"** ;
filter.addArg(REGEXP_KEY, regex);
filter.addArg(REPLACEMENT_KEY, replacement);
routeDefinition.getFilters().add(filter);

return routeDefinition;
});
}
}

CompositeRouteDefinitionLocator

* org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* getRouteDefinitions() 方法,提供统一方法,将组合的 delegates 的路由定义全部返回。

delegates.flatMap会把底层保存的所有RouteDefinitionLocator实现类,把从每一个被观察者接受到的数据,调用getRouteDefinitions,全部组装成Flux<RouteDefinition>

代码如下 :

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {

/**
* RouteDefinitionLocator 数组
*/
private final Flux<RouteDefinitionLocator> delegates ;

public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
this .delegates = delegates;
}

@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return this .delegates .flatMap(RouteDefinitionLocator::getRouteDefinitions);
}

}

RouteDefinition

概述

* 通过RouteDefinitionLocator接口的实现类生成集合Flux<RouteDefinition>

* RouteDefinition只是一个路由的描述,此时还未生成对应的实体类,这个bean定义类似,包含了:

①id:ID 编号,唯一。

②List<PredicateDefinition> predicates:谓语定义数组。请求通过 predicates 判断是否匹配。在 Route 里,PredicateDefinition 转换成 Predicate 。

③List<FilterDefinition> filters:过滤器定义数组。在 Route 里,FilterDefinition 转换成 GatewayFilter 。

④uri:路由向的 URI 。

⑤order:顺序。当请求匹配到多个路由时,使用顺序小的。

* RouteDefinition 提供 text 字符串创建对象,按照一个规则

①text 参数,格式为 {id}={uri},{predicates\[0\]},{predicates1}...${predicatesn} 。可以指定id和predicates,直接使用,隔开

举个例子, "route001=http://127.0.0.1,Host=**.addrequestparameter.org,Path=/get"

②filters和order属性,需要通过setter方法进行设置。

@Validated
public class RouteDefinition {

@NotEmpty
private String id = UUID.randomUUID().toString();

@NotEmpty
@Valid
private List<PredicateDefinition> predicates = new ArrayList<>();

@Valid
private List<FilterDefinition> filters = new ArrayList<>();

@NotNull
private URI uri ;

private int order = 0;

public RouteDefinition() {
}

public RouteDefinition(String text) {
int eqIdx = text.indexOf('=' );
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse RouteDefinition text '" + text

  • "'" + ", must be of the form name=value" );
    }

setId(text.substring(0, eqIdx));

String\[\] args = tokenizeToStringArray(text.substring(eqIdx + 1), "," );

setUri(URI.create(args0));

for (int i = 1; i < args.length ; i++) {
this .predicates .add(new PredicateDefinition(argsi));
}
}

}

PredicateDefinition

* Predicate的定义,保存了如下信息:、

①name :谓语定义名字。通过 name 对应到 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 的实现类。

例如说,name=Query 对应到 QueryRoutePredicateFactory 。

②args:参数数组。例如,name=Host 会转为args={"_genkey_0" : "iocoder.cn"} ,最终匹配请求的 hostname 为 iocoder.cn 。--其中_genkey_i是固定的模式

* 基于text 参数进行规则,格式为 {name}={args0},{args\[1\]}...{argsn} 。

举个例子, "Host=iocoder.cn"

@Validated
public class PredicateDefinition {

@NotNull
private String name ;

private Map<String, String> args = new LinkedHashMap<>();

public PredicateDefinition() {}

public PredicateDefinition(String text) {
int eqIdx = text.indexOf('=' );
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse PredicateDefinition text '"

  • text + "'" + ", must be of the form name=value" );
    }
    setName(text.substring(0, eqIdx));

String\[\] args = tokenizeToStringArray (text.substring(eqIdx + 1), "," );

for (int i = 0; i < args.length ; i++) {
this .args .put(NameUtils.generateName (i), argsi);
}
}
//

}

FilterDefinition

* 过滤器的定义,保存了如下信息:

①name:过滤器定义名字。通过 name 对应到 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 的实现类。

例如说,name=AddRequestParameter 对应到 AddRequestParameterGatewayFilterFactory

②args:参数数组。例如,name=AddRequestParameter / args={"_genkey_0": "foo", "_genkey_1": "bar"} ,添加请求参数 foo 为 bar 。

* 基于text 字符串创建对象。格式为 {name}={args0},{args\[1\]}...{argsn} 。

举个例子, "AddRequestParameter=foo, bar"

@Validated
public class FilterDefinition {

@NotNull
private String name ;

private Map<String, String> args = new LinkedHashMap<>();

public FilterDefinition() {
}

public FilterDefinition(String text) {
int eqIdx = text.indexOf('=' );
if (eqIdx <= 0) {
setName(text);
return ;
}
setName(text.substring(0, eqIdx));

String\[\] args = tokenizeToStringArray (text.substring(eqIdx + 1), "," );

for (int i = 0; i < args.length ; i++) {
this .args .put(NameUtils.generateName (i), argsi);
}
}
//

}

Route

org.springframework.cloud.gateway.route.Route ,路由。

* 对应了RouteDefinition定义,是真正的实体类,里面的PredicateDefinition和FilterDefinition统一会转为对应的实体类

* 可以通过Builder对Route 里属性进行设置,在最终构建

代码如下

public class Route implements Ordered {

/**
* 路由编号
*/
private final String id ;
/**
* 路由向的 URI
*/
private final URI uri ;
/**
* 顺序
*/
private final int order ;
/**
* 谓语数组
*/
private final Predicate<ServerWebExchange> predicate ;
/**
* 过滤器数组
*/
private final List<GatewayFilter> gatewayFilters ;

private Route(String id, URI uri, int order,
AsyncPredicate<ServerWebExchange> predicate,
List<GatewayFilter> gatewayFilters, Map<String, Object> metadata) {
this .id = id;
this .uri = uri;
this .order = order;
this .predicate = predicate;
this .gatewayFilters = gatewayFilters;
this .metadata = metadata;
}

public static Builder builder() {
return new Builder();
}

public static Builder builder(RouteDefinition routeDefinition) {
// @formatter:off
return new Builder().id(routeDefinition.getId())
.uri(routeDefinition.getUri())
.order(routeDefinition.getOrder())
.metadata(routeDefinition.getMetadata());
// @formatter:on
}

//
}

RouteLocator

概述

RouteLocator接口

负责生成路由的最终实体类Route,有如下几种方法

①通过 RouteDefinitionRouteLocator获取RouteDefinition,并转换成 Route 。

②可以通过代码定义自定义路由

public interface RouteLocator {
Flux<Route> getRoutes();
}

RouteDefinitionRouteLocator(核心)

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> GatewayFilters,
List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator,
@Qualifier("webFluxConversionService" ) ConversionService conversionService) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
GatewayFilters, properties, conversionService);
}

主体流程

* 成员变量

①RouteDefinitionLocator routeDefinitionLocator

存储RouteDefinition的对象,比如PropertiesRouteDefinitionLocator从配置文件读取路由配置

②封装了ApplicationEventPublisher、;BeanFactory、Supplier<ConversionService> 、SpelExpressionParser、Supplier<Validator> validator;

主要作用是用于创建Predicate和Filter实现类中的内部Config对象,用于判断结果

③Map<String, RoutePredicateFactory> predicates

Predicate名称关联RoutePredicateFactory实现类,如 Before -> BeforeRoutePredicateFactory

④Map<String, GatewayFilterFactory> gatewayFilterFactories

Filter名称关联GatewayFilterFactory实现类,如AddRequestHeade -> AddRequestHeaderGatewayFilterFactory

⑤GatewayProperties gatewayProperties:配置类

* 构造方法内

①initFactories(predicates)

把传递进来的所有RoutePredicateFactory实现类,按照Predicate名称关联RoutePredicateFactory实现类规则,存储于Map<String, RoutePredicateFactory> predicates变量中

②把传递进来的所有GatewayFilterFactory实现类,按照Filter名称关联GatewayFilterFactory实现类规则,存储于Map<String, GatewayFilterFactory> gatewayFilterFactories变量中

* 实现getRoutes()核心方法获取Flux<Route>(发布者)

①从RouteDefinitionLocator获取Flux<RouteDefinition>再通过convertToRoute方法map操作转为Flux<Route>,这时惰性计算,转换还未开始

Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);

②根据isFailOnRouteDefinitionError,决定如果其中转换出现错误,是否跳过,是的话最终返回的Flux<Route>的onErrorContinue(只打印日志,而不抛出异常)方法即可

* 核心的方法convertToRoute,把一个RouteDefinition转为Route

①AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition),返回配置的Predicate,

  • 从当前的routeDefinition中getPredicates()获取List<PredicateDefinition> predicates,即此有了配置的PredicateDefinition定义

  • 先取第一个PredicateDefinition调用lookup(PredicateDefinition)方法:

  1. 通过Predicate名称从predicates 中获取具体的RoutePredicateFactory实现类,如BeforeRoutePredicateFactory
  2. 通过ConfigurationService(ConfigurationService)构建出RoutePredicateFactory类中内部类Config(流程见下),对应了用户配置的参数值

比如 - Before=2018-12-25T14:33:47.789+08:00。2018-12-25T14:33:47.789+08:00就会作为BeforeRoutePredicateFactory.Config的ZonedDateTime datetime变量中

  1. 使用RoutePredicateFactory.applyAsync,其内调用toAsyncPredicate(apply(config));

apply(config)是每一个xxxPredicateFactory实现类都会实现的抽象方法,返回Predicate<ServerWebExchange>,

例如BeforeRoutePredicateFactory的实现如下,使用GatewayPredicat类型对象返回,其内的test方法就是具体的Predicate判断

这样就组装了Predicate对象,里面用户配置信息Config和具体test判断GatewayPredicat

public Predicate<ServerWebExchange> apply(Config config) {

return new GatewayPredicate() {

@Override

public boolean test(ServerWebExchange serverWebExchange) {

final ZonedDateTime now = ZonedDateTime.now ();

return now.isBefore(config.getDatetime());

}

};

}

d.把这个Predicate调用AsyncPredicate.from(predicate)形成DefaultAsyncPredicate(见下节)

  • 剩下的PredicateDefinition定义一次调用lookup(PredicateDefinition)方法形成DefaultAsyncPredicate。然后第一个DefaultAsyncPredicate以AND的形成串联所有DefaultAsyncPredicate

返回最终的AsyncPredicate<ServerWebExchange>

②getFilters(routeDefinition)把当前routeDefinition中定义的过滤器和默认过滤器,调用loadGatewayFilters转换List<GatewayFilter>,遍历每一个FilterDefinition

  • 通过Filter名称从gatewayFilterFactories 中获取具体的GatewayFilterFactory实现类,如AddRequestHeaderGatewayFilterFactory

  • 通过ConfigurationService(ConfigurationService)构建出GatewayFilterFactory类中内部类Config,对应了用户配置的值(可能没有)

  • 调用GatewayFilterFactory实现类的apply方法返回GatewayFilter,其内容就是过滤的增强处理

GatewayFilter的filter方法会返回Mono<Void>类型,

  • 按照Ordered、编写顺序进行排序

public class AddRequestHeaderGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {

@Override
public GatewayFilter apply(NameValueConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
String value = ServerWebExchangeUtils.expand (exchange, config.getValue());
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), value).build();

return chain.filter(exchange.mutate().request(request).build());
}

@Override
public String toString() {
return filterToStringCreator (AddRequestHeaderGatewayFilterFactory.this )
.append(config.getName(), config.getValue()).toString();
}
};
}

}

③封装为Route

new Route(this.id, this.uri, this.order, predicate,this.gatewayFilters, this.metadata);

public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
public static final String DEFAULT_FILTERS = "defaultFilters" ;
private final RouteDefinitionLocator routeDefinitionLocator ;
private final ConfigurationService configurationService ;
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
private final GatewayProperties gatewayProperties ;

@Deprecated
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties, ConversionService conversionService) {
this .routeDefinitionLocator = routeDefinitionLocator;
this .configurationService = new ConfigurationService();
this .configurationService .setConversionService(conversionService);
initFactories(predicates);
gatewayFilterFactories.forEach(
factory -> this .gatewayFilterFactories .put(factory.name(), factory));
this .gatewayProperties = gatewayProperties;
}

public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties,
ConfigurationService configurationService) {
this .routeDefinitionLocator = routeDefinitionLocator;
// 封装了 ApplicationEventPublisher publisher;BeanFactory beanFactory;Supplier<ConversionService> conversionService;
//SpelExpressionParser parser = new SpelExpressionParser();private Supplier<Validator> validator;
// 主要作用是用于创建内部 Config
this .configurationService = configurationService;
// 例如 BeforeRoutePredicateFactory ,会在 predicates 变量中存储 Before -> BeforeRoutePredicateFactory
initFactories(predicates);
// 同上
gatewayFilterFactories.forEach(
factory -> this .gatewayFilterFactories .put(factory.name(), factory));
this .gatewayProperties = gatewayProperties;
}

@Override
public Flux<Route> getRoutes() {
// RouteDefinitionLocator 获取 Flux<RouteDefinition> 再通过 convertToRoute 方法 Map 转为 Flux<Route>
// 这时惰性计算,转换还未开始
Flux<Route> routes = this .routeDefinitionLocator .getRouteDefinitions()
.map(this ::convertToRoute);

// 如果其中转换出现错误,是否跳过
if (!gatewayProperties .isFailOnRouteDefinitionError()) {
// instead of letting error bubble up, continue
routes = routes.onErrorContinue((error, obj) -> {
// 值打印数据
}
});
}

return routes;
}

private Route convertToRoute(RouteDefinition routeDefinition) {
//Predicate 定义转为 AsyncPredicate<ServerWebExchange>
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
// 转换默认和定义的过滤器为具体的实现类。例如 ResponseHeaderGatewayFilterFactory
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
//new Route(this.id, this.uri, this.order, predicate,this.gatewayFilters, this.metadata);
return Route.async (routeDefinition).asyncPredicate(predicate)
.replaceFilters(gatewayFilters).build();
}

@SuppressWarnings("unchecked" )
List<GatewayFilter> loadGatewayFilters(String id,
List<FilterDefinition> filterDefinitions) {
ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
for (int i = 0; i < filterDefinitions.size(); i++) {
FilterDefinition definition = filterDefinitions.get(i);
GatewayFilterFactory factory = this .gatewayFilterFactories
.get(definition.getName());
if (factory == null ) {
throw new IllegalArgumentException();
}

// 获取配置的 Filter 内部类 Config
Object configuration = this .configurationService .with(factory)
.name(definition.getName())
.properties(definition.getArgs())
.eventFunction((bound, properties) -> new FilterArgsEvent(
RouteDefinitionRouteLocator.this , id, (Map<String, Object>) properties))
.bind();

if (configuration instanceof HasRouteId) {
HasRouteId hasRouteId = (HasRouteId) configuration;
hasRouteId.setRouteId(id);
}

// 直接过滤器的 apply 返回一个 GatewayFilter ,其内的 filter 的方法就是具体的过滤器逻辑
GatewayFilter gatewayFilter = factory.apply(configuration);
if (gatewayFilter instanceof Ordered) {
ordered.add(gatewayFilter);
}
else {
ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
}
}

return ordered;
}

private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
List<GatewayFilter> filters = new ArrayList<>();

// 处理默认的过滤器
if (!this .gatewayProperties .getDefaultFilters().isEmpty()) {
filters.addAll(loadGatewayFilters(routeDefinition.getId(),
new ArrayList<>(this .gatewayProperties .getDefaultFilters())));
}

// 处理调用的过滤器
if (!routeDefinition.getFilters().isEmpty()) {
filters.addAll(loadGatewayFilters(routeDefinition.getId(),
new ArrayList<>(routeDefinition.getFilters())));
}

AnnotationAwareOrderComparator.sort (filters);
return filters;
}

private AsyncPredicate<ServerWebExchange> combinePredicates(
RouteDefinition routeDefinition) {
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
if (predicates == null || predicates.isEmpty()) {
return AsyncPredicate.from (exchange -> true );
}
// 使用第一个 PredicateDefinition 生成 Predicate
AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,predicates.get(0));

// 剩下的 PredicateDefinition 一一生成 Predicate and
// 形成 AndAsyncPredicate ,进行且的判断
// public Publisher<Boolean> apply(T t) {
// return Mono.from(left.apply(t)).flatMap(
// result -> !result ? Mono.just(false) : Mono.from(right.apply(t)));
for (PredicateDefinition andPredicate : predicates.subList(1,
predicates.size())) {
AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
andPredicate);
predicate = predicate.and(found);
}

return predicate;
}

@SuppressWarnings("unchecked" )
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
PredicateDefinition predicate) {
// 获取一个 RoutePredicateFactory ,如 BeforeRoutePredicateFactory
RoutePredicateFactory<Object> factory = this .predicates .get(predicate.getName());
if (factory == null ) {
throw new IllegalArgumentException();
}

// 构建此说需要的配置 Config 内部类,如 oBeforeRoutePredicateFactory.Config
Object config = this .configurationService .with(factory)
.name(predicate.getName())
.properties(predicate.getArgs())
.eventFunction((bound, properties) -> new PredicateArgsEvent(
RouteDefinitionRouteLocator.this , route.getId(), properties))
.bind();
// @formatter:on

// 默认情况下为返回 DefaultAsyncPredicate ,其里面 delegat Predicate 接口实现类(如 GatewayPredicate 里面实现了 test ),
// DefaultAsyncPredicate apply 方法会返回一个 Publisher<Boolean> ,其里面使用 Mono.just(delegate.test(t))
return factory.applyAsync(config);
}

@Override
@Deprecated
public void setBeanFactory/Validator/ApplicationEventPublisher(BeanFactory beanFactory) throws BeansException {
//
}

}

内部config的实例化

* 在RouteDefinitionRouteLocator内把一个RouteDefinition转为Route时,进行了AsyncPredicate<ServerWebExchange>(Predicate实现类串联)的构建,其中Object config的实例流程如下

  • 使用factory.newConfig()获取到指定的配置类,基于反射实现

  • 使用ConfigurationUtils.bind把用户配置属性绑定到配置类中

//RouteDefinitionRouteLocator convertToRoute
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
PredicateDefinition predicate) {
RoutePredicateFactory<Object> factory = this .predicates.get(predicate.getName());
Map<String, String> args = predicate.getArgs();
Map<String, Object> properties = factory.shortcutType().normalize(args, factory,this .parser, this .beanFactory);
Object config = factory.newConfig();
ConfigurationUtils.bind (config, properties, factory.shortcutFieldPrefix(),predicate.getName(), validator, conversionService);
if (this .publisher != null ) {
this .publisher.publishEvent(
new PredicateArgsEvent(this , route.getId(), properties));
}
return factory.applyAsync(config);
}

* RouteDefinitionRouteLocator主要借助ConfigurationService configurationService构建辅助类,with保存了具体的实现类,name保存了predicate的名称,properties保存参数Map<String, String> args

例如配置文件内容

predicates:

  • name: ReadBodyPredicateFactory #TokenRoutePredicateFactory

args: #代表Config的参数

headerName: 'kkk','nnn' #以Map<String, String>存储

存储于PredicateDefinition中:

name:TokenRoutePredicateFactory

args :{"_genkey_0" : "kkk"}

{"_genkey_1" : "nnn"}

* bind方法开始构建,调用normalizeProperties对原始的Map<String, String> args进行转换normalizeProperties

①调用configurable.shortcutType()获取枚举ShortcutType,其中默认的DEFAULT

具体的Predicate实现类可以重写shortcutType() 指定不用的枚举类型

②DEFAULT作用是借助Predicate实现类的shortcutFieldOrder方法,这里指定了内部类属性字段的顺序,应用户进行配置时的顺序一致

把原始的原始的Map<String, String> arg作为Map<字段名称, 配置alue> 形式

* 最后一步借助Bindable实例化Config对象,并基于normalizedProperties绑定变量的值,把属性值绑定为具体的Predicate实现类中

// 构建此说需要的配置 Config 内部类,如 BeforeRoutePredicateFactory.Config
Object config = this .configurationService .with(factory)
.name(predicate.getName())
.properties(predicate.getArgs())
.eventFunction((bound, properties) -> new PredicateArgsEvent(
RouteDefinitionRouteLocator.this , route.getId(), properties))
.bind();

public T bind() {
validate();

if (this .normalizedProperties == null ) {
this .normalizedProperties = normalizeProperties();
}

T bound = doBind();

if (this .eventFunction != null && this .service .publisher != null ) {
ApplicationEvent applicationEvent = this .eventFunction .apply(bound,
this .normalizedProperties );
this .service .publisher .publishEvent(applicationEvent);
}

return bound;
}

@Override
protected Map<String, Object> normalizeProperties() {
if (this .service .beanFactory != null ) {
return this .configurable .shortcutType().normalize(this .properties ,
this .configurable , this .service .parser , this .service .beanFactory );
}
return super .normalizeProperties();
}

@Override
protected T doBind() {
Bindable<T> bindable = Bindable.of (this .configurable .getConfigClass());
T bound = bindOrCreate (bindable, this .normalizedProperties , //properties 转换的
this .configurable .shortcutFieldPrefix(),
/* this.name, */ this .service .validator .get(),// 配置的validator
this .service .conversionService .get());// 配置的 类型转换conversionService

return bound;
}

AsyncPredicate断言链

* 在Route的创建阶段会把所有Predicate以and形式组装成AsyncPredicate<ServerWebExchange>

* 调用AsyncPredicate的apply会得到一个Publisher<Boolean>发布者

一订阅的话就会执行内部的以and形成组成的Predicate实现类集合,执行全部Predicate实现类的apply方法中test结果

* AsyncPredicate接口继承Function,主要默认实现了apply(T t),用于返回一个发布者Publisher<Boolean>

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {..}

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
....
}

* 接口定义了默认的实现类DefaultAsyncPredicate,调用AsyncPredicate.from(Predicate predicate)会把一个具体的predicate实现类会转为AsyncPredicate<ServerWebExchange>

static AsyncPredicate<ServerWebExchange> from(Predicate<? super ServerWebExchange> predicate) {
return new DefaultAsyncPredicate<>(GatewayPredicate.wrapIfNeeded (predicate));
}

①内部管理一个delegate,对应一个具体的Predicate工厂实现类,如BeforeRoutePredicateFactory

②实现了apply方法,以Mono.just(delegate.test(t))返回发布者。这个发布者是数据载体即时的发布者,即在订阅之前delegate.test(t)就已经执行

当用户调用DefaultAsyncPredicate.apply方法时,delegate.test(t)也被调用了,不过此时还没有订阅者

class DefaultAsyncPredicate<T> implements AsyncPredicate<T> {

private final Predicate<T> delegate ;
public DefaultAsyncPredicate(Predicate<T> delegate) {this .delegate = delegate;}

@Override
public Publisher<Boolean> apply(T t) {
return Mono.just (delegate .test(t));
}
}

* 提供and(other AsyncPredicate)、not、or方法把当前的AsyncPredicate与其他的AsyncPredicate进与或非组合判断

①以and为例

default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
return new AndAsyncPredicate<>(this , other);//this代表调用者,即左边的AsyncPredicate,这样就形成了链式编程
}

②AndAsyncPredicate

使用flatMap,接受上一个发布者的结果,进行处理,如果为false,直接返回false,否则执行另一个AsyncPredicate的apply判断

class AndAsyncPredicate<T> implements AsyncPredicate<T> {

private final AsyncPredicate<? super T> left ;

private final AsyncPredicate<? super T> right ;

public AndAsyncPredicate(AsyncPredicate<? super T> left, AsyncPredicate<? super T> right) {

this .left = left;

this .right = right;

}

@Override

public Publisher<Boolean> apply(T t) {

return Mono.from (left .apply(t)).flatMap(

result -> !result ? Mono.just (false ) : Mono.from (right .apply(t)));

}

}

CompositeRouteLocator

组合多种 RouteLocator 的实现类,为 RoutePredicateHandlerMapping 提供统一入口访问路由。代码如下 :

public class CompositeRouteLocator implements RouteLocator {

private final Flux<RouteLocator> delegates ;

public CompositeRouteLocator(Flux<RouteLocator> delegates) {
this .delegates = delegates;
}

// 提供统一方法,将组合的 delegates 的路由全部返回。
@Override
public Flux<Route> getRoutes() {
return this .delegates .flatMap(RouteLocator::getRoutes);
}
}

CachingRouteLocator

在底层委托类的基础上,在提供缓存的功能

public class CachingRouteLocator implements RouteLocator {

private final RouteLocator delegate ;
/**
* 路由缓存
*/
private final AtomicReference<List<Route>> cachedRoutes = new AtomicReference<>();

public CachingRouteLocator(RouteLocator delegate) {
this .delegate = delegate;
// 通过 collectRoutes 方法,从委托类中获取最新的结果,保存到 cachedRoutes
this .cachedRoutes .compareAndSet(null , collectRoutes());
}
private List<Route> collectRoutes() {
List<Route> routes = this .delegate .getRoutes().collectList().block();
// 排序
AnnotationAwareOrderComparator.sort(routes);
return routes;
}

// 接口实现:从缓存中获取即可
@Override
public Flux<Route> getRoutes() {
return Flux.fromIterable(this .cachedRoutes .get());
}

// 监听 org.springframework.context.ApplicationEvent.RefreshRoutesEvent 事件,刷新缓存。
@EventListener(RefreshRoutesEvent.class )
void handleRefresh() {
refresh();
}

public Flux<Route> refresh() {
return Flux.fromIterable(this .cachedRoutes .getAndUpdate(
routes -> CachingRouteLocator.this .collectRoutes()));
}

}

RoutePredicateFactory

概述

* RoutePredicateFactory接口

①核心接口方法,Predicate<ServerWebExchange> apply(C config);表示Predicate的规则判断,

其中参数表示用户配置的信息,一般每一个RoutePredicateFactory实现类都有一个自己的config内部类,表示用户指定的配置信息

②name(),默认的获得 RoutePredicateFactory 的名字的方法。该方法截取类名前半段,例如 QueryRoutePredicateFactory 的结果为 Query

@FunctionalInterface
public interface RoutePredicateFactory {

String PATTERN_KEY = "pattern" ;

// 核心接口方法,表示Predicate的规则判断
Predicate<ServerWebExchange> apply(C config);

// 获得 RoutePredicateFactory 的名字。该方法截取类名前半段,例如 QueryRoutePredicateFactory 的结果为 Query
default String name() {
return NameUtils.normalizePredicateName(getClass());
}

//

}

* 实现类

AbstractRoutePredicateFactory

* 主要继承AbstractConfigurable,用于实例化内部配置类

* configClass表示内部类的的类型,提供例如newConfig()方法借助BeanUtils反射子类自定义configClass并获取实例

public abstract class AbstractRoutePredicateFactory<C> extends AbstractConfigurable<C> implements RoutePredicateFactory<C> {
public AbstractRoutePredicateFactory(Class<C> configClass) {
super (configClass);
}

}

public abstract class AbstractConfigurable<C> implements Configurable<C> {

private Class<C> configClass ;
protected AbstractConfigurable(Class<C> configClass) {
this .configClass = configClass;
}
public Class<C> getConfigClass() {
return configClass ;
}
@Override
public C newConfig() {
return BeanUtils.instantiateClass (this .configClass );
}
@Override
public String toString() {
return new ToStringCreator(this ).append("configClass" , configClass ).toString();
}

}

After / Before / BetweeenRoutePredicateFactory

* 使用

  • After=2017-01-20T17:42:47.789-07:00America/Denver

  • Before=2017-01-20T17:42:47.789-07:00America/Denver

  • Betweeen=2017-01-20T17:42:47.789-07:00America/Denver, 2017-01-21T17:42:47.789-07:00America/Denver

* 实现原理

①内部配置类的Config的ZonedDateTime datetime保存了用户指定的时机

②apply中:基于ZonedDateTime 时间工具类进行时间范围的判断

注:Before/BetweeenRoutePredicateFactory实现类似,略

public class AfterRoutePredicateFactory extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> {

/**
* DateTime key.
*/
public static final String DATETIME_KEY = "datetime" ;

public AfterRoutePredicateFactory() {
super (Config.class );
}

@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList (DATETIME_KEY );
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
final ZonedDateTime now = ZonedDateTime.now ();
return now.isAfter(config.getDatetime());
}

@Override
public String toString() {
return String.format ("After: %s" , config.getDatetime());
}
};
}

public static class Config {

@NotNull
private ZonedDateTime datetime ;

public ZonedDateTime getDatetime() {
return datetime ;
}

public void setDatetime(ZonedDateTime datetime) {
this .datetime = datetime;
}

}

}

HeaderRoutePredicateFactory (Cookie/Host/Method/Query)

* 这些都是请求基本信息的判断,较为简单

ServerWebExchange.getRequest().getHeader/Cookie/Host/Method/ Query等,获取后与配置进行正则匹配

* 例如HeaderRoutePredicateFactory请求指定 Cookie 正则匹配指定值

  • Header=X-Request-Id, \d+

public class HeaderRoutePredicateFactory
extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

public static final String HEADER_KEY = "header" ;
public static final String REGEXP_KEY = "regexp" ;

public HeaderRoutePredicateFactory() {
super (Config.class );
}

@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList (HEADER_KEY , REGEXP_KEY );
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {
boolean hasRegex = !StringUtils.isEmpty (config.regexp );

return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
List<String> values = exchange.getRequest().getHeaders().getOrDefault(config.header , Collections.emptyList ());
if (values.isEmpty()) {return false ;}
if (hasRegex) {
for (int i = 0; i < values.size(); i++) {
String value = values.get(i);
if (value.matches(config.regexp )) {
return true ;
}
}
return false ;
}
return true ;
}
};
}

@Validated
public static class Config {
@NotEmpty
private String header ;
private String regexp ;
...
}

}

PathRoutePredicateFactory

* 请求 Path 进行正则的匹配指定值。

在存在多个匹配表达式是,可以指定当第一个不匹配时候,是否匹配第二个正则

* 注意路径参数的处理,如果存在路径参数,会保存在请求属性中,值为一个map<路径字段名,值>

path=/foo/123 <=> /foo/{segment} --> request请求属性{'segment',123}

public class PathRoutePredicateFactory
extends AbstractRoutePredicateFactory<org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config> {

private static final String MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY = "matchOptionalTrailingSeparator" ;
private PathPatternParser pathPatternParser = new PathPatternParser();
public PathRoutePredicateFactory() {
super (org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config.class );
}
public void setPathPatternParser(PathPatternParser pathPatternParser) {
this .pathPatternParser = pathPatternParser;
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList ("patterns" , MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY );
}
@Override
public ShortcutType shortcutType() {
return ShortcutType.GATHER_LIST_TAIL_FLAG ;
}

@Override
public Predicate<ServerWebExchange> apply(org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config config) {
final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
synchronized (this .pathPatternParser ) {
// 指定匹配表达式集合,指定当第一个不匹配时候,是否匹配第二个正则
pathPatternParser .setMatchOptionalTrailingSeparator(
config.isMatchOptionalTrailingSeparator());
config.getPatterns().forEach(pattern -> {
PathPattern pathPattern = this .pathPatternParser .parse(pattern);
pathPatterns.add(pathPattern);
});
}
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
PathContainer path = parsePath(exchange.getRequest().getURI().getRawPath());
PathPattern match = null ;
for (int i = 0; i < pathPatterns.size(); i++) {
PathPattern pathPattern = pathPatterns.get(i);
if (pathPattern.matches(path)) {
match = pathPattern;
break ;
}
}

if (match != null ) {
// 如果存在路径参数,保存在请求属性中
// 例如 path=/foo/123 <=> /foo/{segment}
PathMatchInfo pathMatchInfo = match.matchAndExtract(path);
putUriTemplateVariables (exchange, pathMatchInfo.getUriVariables());
return true ;
}
else {
return false ;
}
}

};
}

@Validated
public static class Config {

private List<String> patterns = new ArrayList<>();

private boolean matchOptionalTrailingSeparator = true ;

@Deprecated
public String getPattern() {
if (!CollectionUtils.isEmpty (this .patterns )) {
return patterns .get(0);
}
return null ;
}

...
}

}

RemoteAddrRoutePredicateFactory

*匹配请求来源 IP 在指定范围内。支持多个,支持网段

* 基于IpSubnetFilterRule 工具类实现

public class RemoteAddrRoutePredicateFactory
extends AbstractRoutePredicateFactory<RemoteAddrRoutePredicateFactory.Config> {

public RemoteAddrRoutePredicateFactory() {
super (Config.class );
}

@Override
public ShortcutType shortcutType() {
return GATHER_LIST ;
}

@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList ("sources" );
}

@NotNull
private List<IpSubnetFilterRule> convert(List<String> values) {
List<IpSubnetFilterRule> sources = new ArrayList<>();
for (String arg : values) {
addSource(sources, arg);
}
return sources;
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {
List<IpSubnetFilterRule> sources = convert(config.sources );

return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
InetSocketAddress remoteAddress = config.remoteAddressResolver
.resolve(exchange);
if (remoteAddress != null && remoteAddress.getAddress() != null ) {
String hostAddress = remoteAddress.getAddress().getHostAddress();
String host = exchange.getRequest().getURI().getHost();
for (IpSubnetFilterRule source : sources) {
if (source.matches(remoteAddress)) {
return true ;
}
}
}

return false ;
}

};
}

private void addSource(List<IpSubnetFilterRule> sources, String source) {
if (!source.contains("/" )) { // no netmask, add default
source = source + "/32" ;
}

String\[\] ipAddressCidrPrefix = source.split("/" , 2);
String ipAddress = ipAddressCidrPrefix0;
int cidrPrefix = Integer.parseInt (ipAddressCidrPrefix1);

sources.add(
new IpSubnetFilterRule(ipAddress, cidrPrefix, IpFilterRuleType.ACCEPT ));
}

@Validated
public static class Config {

@NotEmpty
private List<String> sources = new ArrayList<>();

@NotNull
private RemoteAddressResolver remoteAddressResolver = new RemoteAddressResolver() {
};

public List<String> getSources() {
return sources ;
}

public Config setSources(List<String> sources) {
this .sources = sources;
return this ;
}

public Config setSources(String... sources) {
this .sources = Arrays.asList (sources);
return this ;
}

public Config setRemoteAddressResolver(
RemoteAddressResolver remoteAddressResolver) {
this .remoteAddressResolver = remoteAddressResolver;
return this ;
}

}

}

GatewayFilter

概述

* DispatcherHandler请求入口会在选定route路由之后,会把Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR)存于请求属性,且hanlderMappring返回了FilteringWebHandler

(注意这是gateway的同名对象,是处理器),接着SimpleHandlerAdapter会调用此FilteringWebHandler的andle(exchange),会从请求属性中获取Route ,同上获取全局GlobalFilter

和此Route 的tGatewayFilte组装成DefaultGatewayFilterChain,开始执行

* 组装滤器链

FilteringWebHandler的handle从请求属性中gatewayRoute获取route,获取其getFilters()全部配置的过滤器GatewayFilter 和全局过滤器GlobalFilter,基于@Order排序,在组装成DefaultGatewayFilterChain

DefaultGatewayFilterChain.filter的方法开始执行每一个过滤器

*全局的GlobalFilter顺序,不是默认的,用户需要注入容器,

①NettyWriteResponseFilter:order(-1),基于Netty的响应处理

②WebClientWriteResponseFilter:order(-1),基于WebClient的响应处理

③RouteToRequestUrlFilter:order(10000),根据匹配的 Route ,计算出请求的地址

...其他的GatewayFilterFactory 实现类:order(1~10000)

④LoadBalancerClientFilter:order(10100),对目标服务器进行负载均衡

...其他的GatewayFilterFactory 实现类:order(10100~Integer.MAX_VALUE)

⑤ForwardRoutingFilter:order(Integer.MAX_VALUE),路由内的重定向处理

⑥NettyRoutingFilter:order(Integer.MAX_VALUE),其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 Netty 实现的 HttpClient 请求后端 Http 服务。

⑦WebClientHttpRoutingFilter:order(Integer.MAX_VALUE),其根据 ws:// / wss:// 前缀( Scheme )过滤处理,代理后端 Websocket 服务

⑧WebsocketRoutingFilter:order(Integer.MAX_VALUE),其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 org.springframework.cloud.gateway.filter.WebClient 实现的 HttpClient 请求后端 Http 服务。

* 在Spring Cloud默认注入这些过滤器:

org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter;

org.springframework.cloud.gateway.filter.ForwardPathFilter;

org.springframework.cloud.gateway.filter.ForwardRoutingFilter;

org.springframework.cloud.gateway.filter.GlobalFilter;

org.springframework.cloud.gateway.filter.NettyRoutingFilter;

org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;

org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter;

org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter;

org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;

org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter;

org.springframework.cloud.gateway.filter.LoadBalancerClientFilter

GatewayFilterFactory 的实现类

请求Header和Parameter相关

* AddRequestHeaderGatewayFilterFactory

添加指定请求Header为指定值。

  • AddRequestHeader=X-Request-Foo, Bar

* RemoveRequestHeaderGatewayFilterFactory

移除指定请求Header为指定值。

* AddResponseHeaderGatewayFilterFactory

添加指定需要Header 为指定值。

*RemoveResponseHeaderGatewayFilterFactory

移除指定需要Header 为指定值。

* SetResponseHeaderGatewayFilterFactory

*RemoveNonProxyHeadersGatewayFilterFactory

移除请求 Proxy 相关的 Header 。默认值为 "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailer", "Transfer-Encoding", "Upgrade"

可以通过 spring.cloud.gateway.filter.remove-non-proxy-headers 配置

* AddRequestParameterGatewayFilterFactory

添加url查询参数

* 基本实现

①Tuple的功能和Predicate的内部配置类Config处理类似

②规则,基于exchange.getRequest().mutate()进行Header 的操作,会基于原ServerHttpRequest 创建创建新的 ServerWebExchange

public class AddRequestHeaderGatewayFilterFactory implements GatewayFilterFactory {

@Override
public List<String> argNames() {
return Arrays.asList(NAME_KEY , VALUE_KEY );
}

@Override
public GatewayFilter apply(Tuple args) {
String name = args.getString(NAME_KEY );
String value = args.getString(VALUE_KEY );

return (exchange, chain) -> { // GatewayFilter
// 创建新的 ServerHttpRequest
ServerHttpRequest request = exchange.getRequest().mutate()
.header(name, value)
.build();

// 创建新的 ServerWebExchange ,提交过滤器链继续过滤
return chain.filter(exchange.mutate().request(request).build());
};
}

//Config
}

Path相关

* RewritePathGatewayFilterFactory

根据配置的正则表达式 regexp ,使用配置的 replacement 重写请求 Path 。从功能目的上类似 《Module ngx_http_rewrite_module》 。

  • RewritePath=/foo/(?<segment>.*), /\\{segment} ,\ 用于替代 $ ,避免和 YAML 语法冲突。

* PrefixPathGatewayFilterFactory,

这个类只需要配置一个prefix参数,它可以给请求的URI添加prefix前缀

* SetPathGatewayFilterFactory

它提供了一种通过允许模板化路径段来操作请求路径的简单方法。 这使用了Spring Framework中的uri模板。 允许多个匹配的段。

predicates:

  • Path=/foo/{segment}

filters:

  • SetPath=/{segment}

对于/ foo / bar的请求路径,这将在发出下游请求之前将路径设置为/ bar。

public class RewritePathGatewayFilterFactory implements GatewayFilterFactory {

public static final String REGEXP_KEY = "regexp" ;
public static final String REPLACEMENT_KEY = "replacement" ;

@Override
public List<String> argNames() {
return Arrays.asList(REGEXP_KEY , REPLACEMENT_KEY );
}

@Override
public GatewayFilter apply(Tuple args) {
final String regex = args.getString(REGEXP_KEY );
// `\\\`** **用于替代** **\`` ,避免和 YAML 语法冲突。
String replacement = args.getString(REPLACEMENT_KEY ).replace("**** ****\\\\**** ****"**** , ****"" );

return (exchange, chain) -> {
ServerHttpRequest req = exchange.getRequest();
// 添加 原始请求 URI GATEWAY_ORIGINAL_REQUEST_URL_ATTR
addOriginalRequestUrl(exchange, req.getURI());
// 重写 Path
String path = req.getURI().getPath();
String newPath = path.replaceAll(regex, replacement);

// 创建新的 ServerHttpRequest
ServerHttpRequest request = req.mutate()
.path(newPath) // 设置 Path
.build();

// 添加 请求 URI GATEWAY_REQUEST_URL_ATTR
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

// 创建新的 ServerWebExchange ,提交过滤器链继续过滤
return chain.filter(exchange.mutate().request(request).build());
};
}
}

HystrixGatewayFilterFactory

* 使用例子,gateway降级后就会将请求转发到http://localhost:9994

①gateway配置

spring:

cloud:

gateway:

routes:

  • id: ingredients

uri: lb://ingredients

predicates:

  • Path=//ingredients/**

filters:

  • name: Hystrix

args:

name: fetchIngredients

fallbackUri: forward:/fallback

  • id: ingredients-fallback

uri: http://localhost:9994

predicates:

  • Path=/fallback

②Hystrix配置

hystrix.command.fetchIngredients.execution.isolation.strategy=...

* 基于 Hystrix ,实现基于 Route 级别的熔断功能

* 流程如下

①使用Setter:配置下HystrixCommand名字取用户配置的name,groupKey为当前过滤器类名

②基于RouteHystrixCommand实现命令的核心执行,继承HystrixObservableCommand,和HystrixCommand区别在于支持hot观察者模式、cold冷观察者模式,其整体逻辑和HystrixCommandl类似,

RouteHystrixCommand主要重写了HystrixObservableCommand的resumeWithFallback以支持对指定的fallbackUri进行DispatcherHandler请求入口的重新处理(对转发的地址进行重写路由)

③需要注意的是:

  • 目前 Hystrix Command 执行超时时,返回客户端 504 状态码,如果使用 JSON 格式作为数据返回,则需要修改下该 HystrixGatewayFilter 的代码实现。

  • 当Hystrix熔断时,最终返回客户端 200 状态码,内容为空,此处建议该 HystrixGatewayFilter 的代码实现。

public class HystrixGatewayFilterFactory implements GatewayFilterFactory {

@Override
public List<String> argNames() {
return Arrays.asList(NAME_KEY );
}

@Override
public GatewayFilter apply(Tuple args) {
// 使用 Setter 配置下 HystrixCommand 名字取用户配置的 name groupKey 为当前过滤器类名
final String commandName = args.getString(NAME_KEY );
final HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName());
final HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandName);
final HystrixObservableCommand.Setter setter = HystrixObservableCommand.Setter
.withGroupKey(groupKey)
.andCommandKey(commandKey);

// 基于 RouteHystrixCommand 实现命令的核心执行,继承 HystrixObservableCommand ,和 HystrixCommand 区别在于支持 hot 观察者模式、 cold 冷观察者模式
// 其整体逻辑和 HystrixCommandl 类似,主要重写了resumeWithFallback以支持对指定的fallbackUri进行DispatcherHandler请求入口的重新处理
return (exchange, chain) -> {
RouteHystrixCommand command = new RouteHystrixCommand(setter, exchange, chain);

return Mono.create(s -> {
// 使用 Hystrix Command Observable 订阅
Subscription sub = command.toObservable().subscribe(s::success, s::error, s::success);
// Mono 取消时,取消 Hystrix Command Observable 的订阅,结束 Hystrix Command 的执行
s.onCancel(sub::unsubscribe);
}).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> {
// Hystrix Command 执行超时时,设置响应 504 状态码,并回写客户端响应 ( exchange.getResponse().setComplete() )
if (throwable instanceof HystrixRuntimeException) {
HystrixRuntimeException e = (HystrixRuntimeException) throwable;
if (e.getFailureType() == TIMEOUT) { // TODO: optionally set status
setResponseStatus(exchange, HttpStatus.GATEWAY_TIMEOUT);
return exchange.getResponse().setComplete();
}
}
// Hystrix Command 发生其他异常时,例如断路器打开,返回 Mono.empty() ,最终返回客户端 200 状态码,内容为空。
return Mono.empty();
// 调用 Mono#then() 方法,参数为空,返回空 Mono ,不再向后发射数据。
}).then();
};
}
}

RouteToRequestUrlFilter

* 根据匹配的 Route ,计算请求的地址。使用Route的url属性,这个会形成uri

* 把原请求的uri的各个部分重写为指定的Route的uri。Route指定的uri没有指定的部分,原请求的uri不会变

* 设置 requestUrl 到 GATEWAY_REQUEST_URL_ATTR 请求属性中

* 注意;如果 Route.uri 属性配置带有 Path ,则会覆盖请求的 Path 。

因为当原Request的uri参数有Path时,新建一个 CompositePathComponentBuilder赋值为原Request的的,因此原有Route.uri被覆盖了无效了

Route.uri:bin.org:80/123

原Request.uri:http://127.0.0.1:8080/test/segment

最终requestUrl:httpbin.org:80/test/segmen...

public class RouteToRequestUrlFilter implements GlobalFilter, Ordered {

private static final Log log = LogFactory.getLog(RouteToRequestUrlFilter.class );
public static final int ROUTE_TO_URL_FILTER_ORDER = 10000;

@Override
public int getOrder() {
return ROUTE_TO_URL_FILTER_ORDER ;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 根据请求域属性GATEWAY_ROUTE_ATTR 获得 之前匹配到的 Route
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (route == null ) {
return chain.filter(exchange);
}
// 拼接 requestUrl ,把原请求的uri的各个部分重写为指定的Route的uri

Route指定的uri没有指定的部分,原请求的uri不会变
URI requestUrl = UriComponentsBuilder.fromHttpRequest(exchange.getRequest())
.uri(route.getUri())
.build(true ) // encoded=true
.toUri();
// 设置 requestUrl GATEWAY_REQUEST_URL_ATTR {@link RewritePathGatewayFilterFactory}
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
// 提交过滤器链继续过滤
return chain.filter(exchange);
}

}

public UriComponentsBuilder uri(URI uri) {
Assert.notNull(uri, "URI must not be null" );
this .scheme = uri.getScheme();
if (uri.isOpaque()) {
this .ssp = uri.getRawSchemeSpecificPart();
resetHierarchicalComponents();
}
else {
if (uri.getRawUserInfo() != null ) {
this .userInfo = uri.getRawUserInfo();
}
if (uri.getHost() != null ) {
this .host = uri.getHost();
}
if (uri.getPort() != -1) {
this .port = String.valueOf (uri.getPort());
}
if (StringUtils.hasLength(uri.getRawPath())) {
this .pathBuilder = new CompositePathComponentBuilder();
this .pathBuilder.addPath(uri.getRawPath());
}
if (StringUtils.hasLength(uri.getRawQuery())) {
this .queryParams.clear();
query(uri.getRawQuery());
}
resetSchemeSpecificPart();
}
if (uri.getRawFragment() != null ) {
this .fragment = uri.getRawFragment();
}
return this ;
}

ForwardRoutingFilter

spring:

application:

name: juejin-gateway

cloud:

gateway:

routes:

=====================================

  • id: forward_sample

uri: forward:///globalfilters

order: 10000

predicates:

  • Path=/globalfilters

filters:

  • PrefixPath=/application/gateway

* 处理流程

我们假定网关端口为 8080 ,当请求 http://127.0.0.1:8080/globalfilters 接口,Spring Cloud Gateway 处理过程如下 :

①匹配到路由 Route (id = forward_sample) 。

②配置的PrefixPathGatewayFilterFactory 将请求改写成 http://127.0.0.1:8080/application/gateway/globalfilters

③ForwardRoutingFilter(顺序晚于PrefixPathGatewayFilterFactory ) 判断有 forward:// 前缀( Scheme ),过滤处理,将请求转发给 DispatcherHandler 重写走handle流程。

④DispatcherHandler 匹配并转发到当前网关实例本地接口 application/gateway/globalfilters 。

注:什么需要配置 PrefixPathGatewayFilterFactory ?需要通过 PrefixPathGatewayFilterFactory 将请求重写路径,以匹配本地 API ,否则 DispatcherHandler 转发会失败。

public class ForwardRoutingFilter implements GlobalFilter, Ordered {

private final DispatcherHandler dispatcherHandler ;
public ForwardRoutingFilter(DispatcherHandler dispatcherHandler) {
this .dispatcherHandler = dispatcherHandler;
}

@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获得 requestUrl
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

// 判断是否能够处理: forward:// 前缀或者该请求暂未被其他 Routing 网关处理
String scheme = requestUrl.getScheme();
if (isAlreadyRouted(exchange) || !scheme.equals("forward" )) {
return chain.filter(exchange);
}

// 设置已经路由, exchange.getAttributes().put(GATEWAY_ALREADY_ROUTED_ATTR, true);
setAlreadyRouted(exchange);

// DispatcherHandler 匹配并转发到当前网关实例本地接口
return this .dispatcherHandler.handle(exchange);
}
}

LoadBalancerClientFilter

根据 lb:// 前缀过滤处理,使用 serviceId 选择一个服务实例,从而实现负载均衡。

* 获得 URL 。只处理 lb:// 为前缀( Scheme )的地址。

* 调用 ServerWebExchangeUtils#addOriginalRequestUrl(...) 添加原始请求 URI 到 GATEWAY_ORIGINAL_REQUEST_URL_ATTR

* 调用 LoadBalancerClient#choose(String) 方法,获得一个服务实例( ServiceInstance ) ,从而实现负载均衡。

例如基于ribbon实现的负载均衡器,RibbonLoadBalancerClient实现类

* 获取到服务实例uri后,覆盖原请求uri的scheme、host、port即可

public class LoadBalancerClientFilter implements GlobalFilter, Ordered {

public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
private final LoadBalancerClient loadBalancer ;
public LoadBalancerClientFilter(LoadBalancerClient loadBalancer) {
this .loadBalancer = loadBalancer;
}

@Override
public int getOrder() {
return LOAD_BALANCER_CLIENT_FILTER_ORDER ;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获得 URL
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
if (url == null || !url.getScheme().equals("lb" )) {
return chain.filter(exchange);
}
// 添加 原始请求 URI GATEWAY_ORIGINAL_REQUEST_URL_ATTR
//preserve the original url
addOriginalRequestUrl(exchange, url);

log.trace("LoadBalancerClientFilter url before: " + url);

// 获取 服务实例
final ServiceInstance instance = loadBalancer.choose(url.getHost());
if (instance == null ) {
throw new NotFoundException("Unable to find instance for " + url.getHost());
}

/*URI uri = exchange.getRequest().getURI();
URI requestUrl = loadBalancer.reconstructURI(instance, uri);*/
URI requestUrl = UriComponentsBuilder.fromUri(url)
.scheme(instance.isSecure()? "https" : "http" ) //TODO: support websockets
.host(instance.getHost())
.port(instance.getPort())
.build(true )
.toUri();
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);

// 添加 请求 URI GATEWAY_REQUEST_URL_ATTR
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);

// 提交过滤器链继续过滤
return chain.filter(exchange);
}

}

RequestRateLimiterGatewayFilterFactory

RequestRateLimiterGatewayFilter 使用 Redis + Lua 实现分布式限流。

而限流的粒度,例如 URL / 用户 / IP 等,通过 org.springframework.cloud.gateway.filter.ratelimit.KeyResolver 实现类决定

filters:

  • RequestRateLimiter=10, 20, #{@remoteAddrKeyResolver}

自定义 KeyResolver

实现一个使用请求 IP 作为限流键的 KeyResolver

@Bean(name = RemoteAddrKeyResolver.BEAN_NAME )
@ConditionalOnBean(RateLimiter.class )
public RemoteAddrKeyResolver remoteAddrKeyResolver() {
return new RemoteAddrKeyResolver();
}

public class RemoteAddrKeyResolver implements KeyResolver {

public static final String BEAN_NAME = "remoteAddrKeyResolver" ;
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}

}

处理流程

* 配置文件中指定了参数

①replenishRate:qps

②burstCapacity:桶的上限

③keyResolver:token的维度,如ip。

* 调用rateLimiter.isAllowed进行限处理

rateLimiter 属性,限流器。默认情况下,使用 RedisRateLimiter,在自动配置类中可以自定义指定

* 基于redis的令牌算法实现

①Redis会为每一个keyResolver的值对应一个令牌桶,如ip1和ip2使用不同的桶,用户传入配置的keyResolver可以解析处理桶的id

②用户还需要根据配置,给redis传递qps、桶的上限,已经此桶id最后一次添加令牌的时机

注:不能在 Redis Lua中 使用 TIME 获取时间戳,因此只好从应用获取然后传入,在某些极端情况下(机器时钟不准的情况下),限流会存在一些小问题

③在redis基于LUA实现了令牌桶的算法流程(略)

与基本的令牌桶的算法不同的是,redis需要计算消耗整个令牌桶填充需要多久时间ttl ,单位:秒。最为桶在redis的过期时间

local fill_time = capacity/rate,即桶大小/qps

local ttl = math.floor(fill_time*2),在乘2

redis.call("setex", tokens_key, ttl, new_tokens)

public class RequestRateLimiterGatewayFilterFactory implements GatewayFilterFactory {

public static final String KEY_RESOLVER_KEY = "keyResolver" ;

private final RateLimiter rateLimiter;
private final KeyResolver defaultKeyResolver;

public RequestRateLimiterGatewayFilterFactory(RateLimiter rateLimiter,
KeyResolver defaultKeyResolver) {
this .rateLimiter = rateLimiter;
this .defaultKeyResolver = defaultKeyResolver;
}

@Override
public List<String> argNames() {
return Arrays.asList(
RedisRateLimiter.REPLENISH_RATE_KEY,
RedisRateLimiter.BURST_CAPACITY_KEY,
KEY_RESOLVER_KEY
);
}

@Override
public boolean validateArgs() {
return false ;
}

@SuppressWarnings("unchecked" )
@Override
public GatewayFilter apply(Tuple args) {
validateMin(2, args);

// 获得 KeyResolver
KeyResolver keyResolver;
if (args.hasFieldName(KEY_RESOLVER_KEY )) {
keyResolver = args.getValue(KEY_RESOLVER_KEY, KeyResolver.class );
} else {
keyResolver = defaultKeyResolver;
}

return (exchange, chain) -> keyResolver.resolve(exchange).flatMap(key ->
// TODO: if key is empty?
rateLimiter.isAllowed(key, args).flatMap(response -> {
// TODO: set some headers for rate, tokens left

// 允许访问
if (response.isAllowed()) {
return chain.filter(exchange);
}

// 被限流,不允许访问
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}));
}

}

NettyRoutingFilter 转发到后端

* 一般位于过滤器链的最后一个,负责访问最终url

* Netty 路由网关过滤器。其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 Netty 实现的 HttpClient 请求后端 Http 服务

基于Netty实现的HttpClient,在自动配置中可以指定

* NettyWriteResponseFilter是与 NettyRoutingFilter 成对使用的网关过滤器。其将 NettyRoutingFilter 请求后端 Http 服务的响应写回客户端。

主要这里的两个不同的链路:原请求和响应、以及Netty 发起的请求和响应

* 处理流程

①获得 requestUrl

②判断是否能够处理

  • http:// 或者 https:// 前缀( Scheme ) 。

  • 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理

③获取原请求对象,以获取Method、url、请求头组成httpHeaders(可以自定义过滤)

④开始发起请求

  • 使用Netty实现的ttpClient

  • 创建 Netty的Request 对象,调用send发送

⑤doOnNext成功发送数据时触发,res为Netty client的响应,这些处理是不会阻塞的,因为此时还没有读取转发请求的响应

  • 获取原响应,将 Netty Response 的响应头和响应状态赋值给原响应

  • 设置 Netty Response 到 CLIENT_RESPONSE_ATTR,最后NettyWriteResponseFilter会进行处理

public class NettyRoutingFilter implements GlobalFilter, Ordered {

// 基于 Netty 实现的 HttpClient, 在自动配置中可以指定
private final HttpClient httpClient ;

public NettyRoutingFilter(HttpClient httpClient) {
this .httpClient = httpClient;
}

// 返回顺序为 Integer.MAX_VALUE 最后一个
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获得 requestUrl
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

// 判断是否能够处理
// http:// 或者 https:// 前缀 ( Scheme )
// 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理
String scheme = requestUrl.getScheme();
if (isAlreadyRouted(exchange) || (!scheme.equals("http" ) && !scheme.equals("https" ))) {
return chain.filter(exchange);
}
// 设置已经路由
setAlreadyRouted(exchange);

// 获取原请求对象,以获取如下信息
ServerHttpRequest request = exchange.getRequest();
// Request Method
final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());
// 获得 url
final String url = requestUrl.toString();
// 获取员请求头组成 httpHeaders
final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
request.getHeaders().forEach(httpHeaders::set);

// 开始发起请求
// 创建 Netty Request 对象
return this .httpClient .request(method, url, req -> {
final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)
.failOnClientError(false ) //code >= 400 clientError 标志为 true, 才会抛出异常
.headers(httpHeaders);

// 请求类型为表单的处理
if (MediaType.APPLICATION_FORM_URLENCODED.includes(request.getHeaders().getContentType())) {
return exchange.getFormData()
.flatMap(map -> proxyRequest.sendForm(form -> {
for (Map.Entry<String, List<String>> entry: map.entrySet()) {
for (String value : entry.getValue()) {
form.attr(entry.getKey(), value);
}
}
}).then())
.then(chain.filter(exchange));
}

// 其他请求类:发送请求 Header 、发送请求 Body
return proxyRequest.sendHeaders() //I shouldn't need this
.send(request.getBody()
.map(DataBuffer::asByteBuffer) // Flux<DataBuffer> => ByteBuffer
.map(Unpooled::wrappedBuffer)); // ByteBuffer => Flux<DataBuffer>
// 成功发送数据时触发, res Netty client 的响应,即上面的气你执行例如
}).doOnNext(res -> {
// 获取原响应
ServerHttpResponse response = exchange.getResponse();
// Netty Response 的响应头和响应状态赋值给原响应
HttpHeaders headers = new HttpHeaders();
res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
response.getHeaders().putAll(headers);
response.setStatusCode(HttpStatus.valueOf(res.status().code()));
// 设置 Netty Response CLIENT_RESPONSE_ATTR ,最后 NettyWriteResponseFilter 会进行处理
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
}).then(chain.filter(exchange));
}
}

NettyWriteResponseFilter

* 过滤器量的顺序是第一个,都是不处理前置,只处理过滤器后置,就是说他是这个过滤器链拦截的最后一步

* 作用是Netty 回写响应网关过滤器,与NettyRoutingFilter是匹配成对的

* 流程如下:

①调用 #then(Mono) 方法,实现 After Filter 逻辑。

②从 CLIENT_RESPONSE_ATTR 中,获得 Netty Response 。这是NettyRoutingFilter保存的

③将 Netty Response 写回给客户端

public class NettyWriteResponseFilter implements GlobalFilter, Ordered {

public static final int WRITE_RESPONSE_FILTER_ORDER = -1;

@Override
public int getOrder() {
return WRITE_RESPONSE_FILTER_ORDER ;

public int getOrder() {
return WRITE_RESPONSE_FILTER_ORDER ;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.defer (() -> {
// 获得 Netty Response
HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
if (clientResponse == null ) {
return Mono.empty ();
}
// 获取网关原请求的响应
ServerHttpResponse response = exchange.getResponse();

// Netty Response 写回给客户端。
NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();
final Flux<NettyDataBuffer> body = clientResponse.receive() //此时就可能造成阻塞了
.retain() // ByteBufFlux => ByteBufFlux
.map(factory::wrap); // ByteBufFlux => Flux<NettyDataBuffer>
return response.writeWith(body);
}));
}

}

相关推荐
辰海Coding2 小时前
MiniSpring框架学习笔记-JDBC 访问框架:如何抽取 JDBC 模板并隔离数据库?
java·数据库·笔记·学习·spring
白露与泡影2 小时前
Java 8老系统旁路接入AI Gateway:不升级JDK也能用AI
java·人工智能·gateway
摇滚侠2 小时前
Spring 零基础入门到进阶 基于 XML 管理 Bean 29-37
xml·java·数据库·后端·spring·intellij-idea
我登哥MVP2 小时前
Spring Boot 从“会用”到“精通”:内容协商原理
java·spring boot·后端·spring·java-ee·maven·lua
宸津-代码粉碎机3 小时前
Spring AI企业级实战|Agent长期记忆持久化落地,彻底解决多轮对话上下文丢失问题
java·开发语言·人工智能·后端·python·spring
云烟成雨TD3 小时前
Spring AI 1.x 系列【58】提示词工程(Prompt Engineering)
java·人工智能·spring
總鑽風3 小时前
[特殊字符] Spring AI Alibaba企业级智能助手落地实践
java·人工智能·spring
Flittly3 小时前
【AgentScope Java新手村系列】(1)框架简介与环境搭建
java·spring boot·笔记·spring·ai
2601_961845423 小时前
2026四级作文预测26年|英语四级写作范文+模板PDF
java·数据库·spring·eclipse·pdf·tomcat·hibernate