spring cloud gateway 作為新一代的微服務(wù)網(wǎng)關(guān)已經(jīng)發(fā)布了一段時(shí)間,我從7月份開(kāi)始使用到現(xiàn)在已經(jīng)4個(gè)月了。但是我一直處于一種只會(huì)使用,原理一知半解的水平。我們小組作為公司微服務(wù)產(chǎn)品的實(shí)踐者,我自己作為組中一員完成了spring cloud gateway的開(kāi)發(fā),也解決了很多棘手的問(wèn)題,卻對(duì)它的原理和啟動(dòng)流程一知半解,好幾次就是因?yàn)椴涣私馑膯?dòng)流程,導(dǎo)致開(kāi)發(fā)受挫,進(jìn)度緩慢?,F(xiàn)在正值閑時(shí),正好看一下相關(guān)的源碼,理解他的啟動(dòng)流程。本文基于spring cloud Finchley.RELEASE版本,最新的SR2版本一些內(nèi)容有改變,但總體改變不大。
首先是網(wǎng)關(guān)的包結(jié)構(gòu)

其中actuate中定義了一個(gè)叫GatewayControllerEndpoint的類(lèi),這個(gè)類(lèi)提供一些對(duì)外的接口,可以獲取網(wǎng)關(guān)的一些信息,比如路由的信息,改變路由地址等等。
config中定義了一些啟動(dòng)時(shí)去加載的類(lèi),配置路由信息和讀取你的配置文件就在這里完成。
discovery中定義了注冊(cè)中心相關(guān)的內(nèi)容,包括注冊(cè)中心的路由等。
event定義了一些事件他們都繼承自ApplicationEvent,對(duì)事件發(fā)布不了解的可以去看看spring的代碼。
filter中定義了spring cloud gateway實(shí)現(xiàn)的一些過(guò)濾器。
handler中定義了很多Predicate相關(guān)的Factory
route就是我們路由的相關(guān)
support是工具包等。
下面就是gateway啟動(dòng)流程的分析了
config包

網(wǎng)關(guān)啟動(dòng)第一步加載的就是去加載config包下的幾個(gè)類(lèi)。

這幾個(gè)類(lèi)就定義了網(wǎng)關(guān)需要加載的配置項(xiàng)。
在我第一次做網(wǎng)關(guān)開(kāi)發(fā)的時(shí)候我引入了spring-boot-starter-web的依賴(lài),這樣是會(huì)報(bào)錯(cuò)的,因?yàn)間ateway是基于spring-webflux開(kāi)發(fā)的,他依賴(lài)的DispatcherHandler就和我們web里的DispatcherServlet一樣的功能。
這里的GatewayClassPathWarningAutoConfiguration這個(gè)類(lèi),就指明了我們需要什么不需要什么,他加載于GatewayAutoConfiguration之前,如果DispatcherServlet存在,就會(huì)給與警告,同樣的DispatcherHandler不存在也會(huì)警告。
@Configuration
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {
private static final Log log = LogFactory.getLog(GatewayClassPathWarningAutoConfiguration.class);
private static final String BORDER = "\n\n**********************************************************\n\n";
@Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
protected static class SpringMvcFoundOnClasspathConfiguration {
public SpringMvcFoundOnClasspathConfiguration() {
log.warn(BORDER+"Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "+
"Please remove spring-boot-starter-web dependency."+BORDER);
}
}
@Configuration
@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這個(gè)是gateway負(fù)載均衡的過(guò)濾器實(shí)現(xiàn)的加載,他將LoadBalancerClientFilter 注入到了容器中,這個(gè)過(guò)濾器后面再說(shuō)。
@Configuration
@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureAfter(RibbonAutoConfiguration.class)
public class GatewayLoadBalancerClientAutoConfiguration {
// GlobalFilter beans
@Bean
@ConditionalOnBean(LoadBalancerClient.class)
public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
return new LoadBalancerClientFilter(client);
}
}
之后便是我們的GatewayAutoConfiguration正式加載了,這個(gè)里面定義了非常多的內(nèi)容,我們大部分用到的過(guò)濾器,過(guò)濾器工廠(chǎng)都是在這里構(gòu)建的。包括之前的gatewayControllerEndpoint也是在這里注入容器中的。這個(gè)類(lèi)的定義很長(zhǎng),我就不再這里都放了,列舉幾個(gè)。
@Configuration
//開(kāi)啟網(wǎng)關(guān),不寫(xiě)默認(rèn)為true
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
@Configuration
@ConditionalOnClass(HttpClient.class)
protected static class NettyConfiguration {
@Bean
@ConditionalOnMissingBean
public HttpClient httpClient(@Qualifier("nettyClientOptions") Consumer<? super HttpClientOptions.Builder> options) {
return HttpClient.create(options);
}
... //還有很多 這里不列舉了。我們都知道spring cloud 是基于Netty實(shí)現(xiàn)的,這里他這個(gè)靜態(tài)內(nèi)部類(lèi)就是初始化netty需要的東西。
}
//初始化了加載配置文件的對(duì)象,建立route
@Bean
public GatewayProperties gatewayProperties() {
return new GatewayProperties();
}
//初始化請(qǐng)求轉(zhuǎn)發(fā) 過(guò)濾器
@Bean
@ConditionalOnProperty(name = "spring.cloud.gateway.forwarded.enabled", matchIfMissing = true)
public ForwardedHeadersFilter forwardedHeadersFilter() {
return new ForwardedHeadersFilter();
}
//最后初始化gatewayControllerEndpoint 這里注意只有引入spring-boot-starter-actuator他才會(huì)加載
@Configuration
@ConditionalOnClass(Health.class)
protected static class GatewayActuatorConfiguration {
@Bean
@ConditionalOnEnabledEndpoint
public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters,
List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter,
RouteLocator routeLocator) {
return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator);
}
}
這里注意我們通過(guò)注冊(cè)中心發(fā)現(xiàn)的路由不是在config包下定義的而是在discovery包下GatewayDiscoveryClientAutoConfiguration實(shí)現(xiàn)了從注冊(cè)中心發(fā)現(xiàn)內(nèi)容
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
@Bean public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}
}
這些注冊(cè)完畢后,我們的配置文件就開(kāi)始讀取了,

這兩個(gè)中定義了我們配置文件的讀取規(guī)則,其中DiscoveryLocatorProperties都有默認(rèn)的值,我們可以不用關(guān)心。GatewayProperties比較重要
@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
@NotNull
@Valid
private List<RouteDefinition> routes = new ArrayList<>();
/**
* List of filter definitions that are applied to every route.
*/
private List<FilterDefinition> defaultFilters = new ArrayList<>();
private List<MediaType> streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM,
MediaType.APPLICATION_STREAM_JSON);
}
這里就定義了我們配置文件里的所有路由信息,讀取完成后,接下來(lái)就要變成真正的路由信息了。
這里就要說(shuō)一下 RouteLocator接口,這個(gè)接口提供了一個(gè)getRoutes()方法返回一個(gè)Flux<Route>所以,他的實(shí)現(xiàn)中就定義了讀取配置文件轉(zhuǎn)成路由的關(guān)鍵。
public interface RouteLocator {
Flux<Route> getRoutes();
}
我們先看從配置文件中加載的路由信息也就是他的實(shí)現(xiàn)RouteDefinitionRouteLocator
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
protected final Log logger = LogFactory.getLog(getClass());
private final RouteDefinitionLocator routeDefinitionLocator;
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
private final GatewayProperties gatewayProperties;
private final SpelExpressionParser parser = new SpelExpressionParser();
private BeanFactory beanFactory;
private ApplicationEventPublisher publisher;
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties) {
this.routeDefinitionLocator = routeDefinitionLocator;
initFactories(predicates);
gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
...
}
我們定位到他的構(gòu)造方法,debug啟動(dòng)

發(fā)現(xiàn)這個(gè)類(lèi)的一個(gè)屬性routeDefinitionLocator中已經(jīng)定義了我們的路由,只不過(guò)是代理對(duì)象。 這個(gè)屬性所對(duì)應(yīng)的接口RouteDefinitionLocator有很多種實(shí)現(xiàn)

我們現(xiàn)在看PropertiesRouteDefinitionLocator,這里
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());
}
}
他的構(gòu)造方法讀取了GatewayProperties ,所以到這里我們的路由就已經(jīng)存在了。通過(guò)他的getRoutes()方法,我們就能方便的取出所有定義的路由信息了
而他的getRoutes()方法又是這樣定義的
@Override
public Flux<Route> getRoutes() {
return this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute)
//TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
return route;
});
}
routeDefinitionLocator.getRouteDefinitions()返回從配置文件中讀取的路由轉(zhuǎn)換成 Flux<RouteDefinition> 再通過(guò)convertToRoute轉(zhuǎn)換成路由對(duì)象的數(shù)組,封裝成Flux()至此,配置文件中讀取路由信息就結(jié)束了。
接下來(lái)我們來(lái)解釋通過(guò)注冊(cè)中心的方式接受的路由信息。這里由一個(gè)叫DiscoveryClientRouteDefinitionLocator的類(lèi)來(lái)實(shí)現(xiàn),他同樣實(shí)現(xiàn)了RouteDefinitionLocator接口,能夠返回Flux<RouteDefinition>
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
private final DiscoveryClient discoveryClient;
private final DiscoveryLocatorProperties properties;
private final String routeIdPrefix;
public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
// 服務(wù)發(fā)現(xiàn)信息
this.discoveryClient = discoveryClient;
//這個(gè)配置是前面說(shuō)過(guò)的DiscoveryLocatorProperties
this.properties = properties;
if (StringUtils.hasText(properties.getRouteIdPrefix())) {
this.routeIdPrefix = properties.getRouteIdPrefix();
} else {
this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
}
}
//這個(gè)是核心
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
SimpleEvaluationContext evalCtxt = SimpleEvaluationContext
.forReadOnlyDataBinding()
.withInstanceMethods()
.build();
SpelExpressionParser parser = new SpelExpressionParser();
Expression includeExpr = parser.parseExpression(properties.getIncludeExpression());
Expression urlExpr = parser.parseExpression(properties.getUrlExpression());
return Flux.fromIterable(discoveryClient.getServices())
.map(discoveryClient::getInstances)
.filter(instances -> !instances.isEmpty())
.map(instances -> instances.get(0))
.filter(instance -> {
Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);
if (include == null) {
return false;
}
return include;
})
.map(instance -> {
String serviceId = instance.getServiceId();
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(this.routeIdPrefix + serviceId);
String uri = urlExpr.getValue(evalCtxt, instance, String.class);
routeDefinition.setUri(URI.create(uri));
final ServiceInstance instanceForEval = new DelegatingServiceInstance(instance, properties);
for (PredicateDefinition original : this.properties.getPredicates()) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {
String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);
predicate.addArg(entry.getKey(), value);
}
routeDefinition.getPredicates().add(predicate);
}
for (FilterDefinition original : this.properties.getFilters()) {
FilterDefinition filter = new FilterDefinition();
filter.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {
String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);
filter.addArg(entry.getKey(), value);
}
routeDefinition.getFilters().add(filter);
}
return routeDefinition;
});
}
當(dāng)我們調(diào)用到getRouteDefinitions的時(shí)候,他通過(guò)discoveryClient轉(zhuǎn)換出了服務(wù)發(fā)現(xiàn)中心的服務(wù)路由

注意這里他沒(méi)有被轉(zhuǎn)換為Flux<Route>而是保留為Flux<RouteDefinition> 這是一個(gè)坑,我們前期很多時(shí)候去找Route發(fā)現(xiàn)根本就沒(méi)有從服務(wù)注冊(cè)中心拉下來(lái)的,現(xiàn)在才知道,他壓根就沒(méi)去轉(zhuǎn)。
到這里,我們的路由信息就加載完畢了,網(wǎng)關(guān)也就啟動(dòng)完成了,之后就是發(fā)送請(qǐng)求過(guò)濾器發(fā)功的時(shí)候了。
我們第一個(gè)關(guān)注的類(lèi)就是DispatcherHandler,這個(gè)類(lèi)提供的handle()方法,封裝了我們之后所有的handlerMappings
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
...
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
ServerHttpRequest request = exchange.getRequest();
logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
}
if (this.handlerMappings == null) {
return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
...
}
這里會(huì)真正的調(diào)用我們前面注冊(cè)的route 的那些 getRouteDefinitions()方法,具體的我也沒(méi)看明白,大概就是封裝了這些Mapping進(jìn)入之后的過(guò)濾鏈中

之后就到了FilteringWebHandler類(lèi),他的handler方法封裝了過(guò)濾器進(jìn)去
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//h獲取到當(dāng)前訪(fǎng)問(wèn)的路由對(duì)象
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//獲取當(dāng)前已經(jīng)存在的 過(guò)濾器 也就是配置的默認(rèn)過(guò)濾器
List<GatewayFilter> gatewayFilters = route.getFilters();
//獲取全局過(guò)濾器
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
//按order排序
AnnotationAwareOrderComparator.sort(combined);
logger.debug("Sorted gatewayFilterFactories: "+ combined);
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
這里的全局過(guò)濾器包括除了我標(biāo)記的兩個(gè)以外的所有過(guò)濾器,之后再介紹

最后按照order排序后的過(guò)濾器順序?yàn)?/p>

之后就真正的開(kāi)始進(jìn)入過(guò)濾鏈了 排除掉我們自己實(shí)現(xiàn)的過(guò)濾器 第一個(gè)進(jìn)入的是AdaptCachedBodyGlobalFilter
他用來(lái)緩存我們的requestBody
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Flux<DataBuffer> body = exchange.getAttributeOrDefault(CACHED_REQUEST_BODY_KEY, null);
if (body != null) {
//封裝 ServerHttpRequest 使得requestBody 能夠復(fù)寫(xiě)
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return body;
}
};
return chain.filter(exchange.mutate().request(decorator).build());
}
return chain.filter(exchange);
}
然后進(jìn)入的是NettyWriteResponseFilter 這個(gè)過(guò)濾器實(shí)現(xiàn)的是返回response 也就是請(qǐng)求完成后返回的對(duì)象。他這里巧妙的使用then()
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// NOTICE: nothing in "pre" filter stage as CLIENT_RESPONSE_ATTR is not added
// then 當(dāng)filter完成后執(zhí)行,也就是過(guò)濾鏈執(zhí)行完畢,返回結(jié)果的時(shí)候
return chain.filter(exchange).then(Mono.defer(() -> {
HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
if (clientResponse == null) {
return Mono.empty();
}
log.trace("NettyWriteResponseFilter start");
ServerHttpResponse response = exchange.getResponse();
NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();
//TODO: what if it's not netty
final Flux<NettyDataBuffer> body = clientResponse.receive()
.retain() //TODO: needed?
.map(factory::wrap);
MediaType contentType = response.getHeaders().getContentType();
return (isStreamingMediaType(contentType) ?
response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body));
}));
}
后面就是返回結(jié)果了 沒(méi)什么可說(shuō)的。之后的過(guò)濾器我就不一個(gè)一個(gè)說(shuō)了,講講比較重要的。
RouteToRequestUrlFilter我在注釋上標(biāo)明了,當(dāng)前uri的值
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (route == null) {
return chain.filter(exchange);
}
log.trace("RouteToRequestUrlFilter start");\
// http://localhost:8804/cydOrganization/getOrgTreeList
URI uri = exchange.getRequest().getURI();
boolean encoded = containsEncodedParts(uri);
// lb://BASE-API-WEB
URI routeUri = route.getUri();
if (hasAnotherScheme(routeUri)) {
// this is a special url, save scheme to special attribute
// replace routeUri with schemeSpecificPart
exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());
routeUri = URI.create(routeUri.getSchemeSpecificPart());
}
// lb://BASE-API-WEB:8804/cydOrganization/getOrgTreeList
URI requestUrl = UriComponentsBuilder.fromUri(uri)
.uri(routeUri)
.build(encoded)
.toUri();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
return chain.filter(exchange);
}
最后他將url拼裝成了我們需要的,能夠做服務(wù)發(fā)現(xiàn)的url,這時(shí)他就會(huì)進(jìn)入LoadBalancerClientFilter 同樣我標(biāo)注url的變化
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// lb://BASE-API-WEB:8804/cydOrganization/getOrgTreeList 剛才我們封裝完畢的url
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
return chain.filter(exchange);
}
//preserve the original url
addOriginalRequestUrl(exchange, url);
log.trace("LoadBalancerClientFilter url before: " + url);
// RibbonServer{serviceId='BASE-API-WEB', server=192.168.47.1:12993, secure=false, metadata={}}
final ServiceInstance instance = loadBalancer.choose(url.getHost());
if (instance == null) {
throw new NotFoundException("Unable to find instance for " + url.getHost());
}
// http://localhost:8804/cydOrganization/getOrgTreeList
URI uri = exchange.getRequest().getURI();
// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
// if the loadbalancer doesn't provide one.
String overrideScheme = null;
if (schemePrefix != null) {
overrideScheme = url.getScheme();
}
// http://192.168.47.1:12993/cydOrganization/getOrgTreeList 到這時(shí) 這個(gè)地址已經(jīng)是正確的訪(fǎng)問(wèn)地址了。
URI requestUrl = loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
return chain.filter(exchange);
}
最后進(jìn)入NettyRoutingFilter 這個(gè)filter真正做請(qǐng)求的發(fā)送,他使用HttpClient進(jìn)行請(qǐng)求的發(fā)送。這個(gè)類(lèi)不是很長(zhǎng) 我就都拷過(guò)來(lái)
public class NettyRoutingFilter implements GlobalFilter, Ordered {
private final HttpClient httpClient;
private final ObjectProvider<List<HttpHeadersFilter>> headersFilters;
public NettyRoutingFilter(HttpClient httpClient,
ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
this.httpClient = httpClient;
this.headersFilters = headersFilters;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// http://192.168.47.1:12993/cydOrganization/getOrgTreeList 我們剛才處理好的url
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
String scheme = requestUrl.getScheme();
//必須是 http 或者 https 和沒(méi)有被路由
if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {
return chain.filter(exchange);
}
// 設(shè)置為已經(jīng)路由,防止請(qǐng)求重復(fù)路由
setAlreadyRouted(exchange);
ServerHttpRequest request = exchange.getRequest();
final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());
final String url = requestUrl.toString();
HttpHeaders filtered = filterRequest(this.headersFilters.getIfAvailable(),
exchange);
final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
filtered.forEach(httpHeaders::set);
String transferEncoding = request.getHeaders().getFirst(HttpHeaders.TRANSFER_ENCODING);
boolean chunkedTransfer = "chunked".equalsIgnoreCase(transferEncoding);
boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
//到這里發(fā)送http請(qǐng)求
return this.httpClient.request(method, url, req -> {
final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)
.headers(httpHeaders)
.chunkedTransfer(chunkedTransfer)
.failOnServerError(false)
.failOnClientError(false);
if (preserveHost) {
String host = request.getHeaders().getFirst(HttpHeaders.HOST);
proxyRequest.header(HttpHeaders.HOST, host);
}
return proxyRequest.sendHeaders() //I shouldn't need this
.send(request.getBody().map(dataBuffer ->
((NettyDataBuffer)dataBuffer).getNativeBuffer()));
}).doOnNext(res -> { //接受請(qǐng)求返回結(jié)果
ServerHttpResponse response = exchange.getResponse();
// put headers and status so filters can modify the response
HttpHeaders headers = new HttpHeaders();
res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
// 這里可能導(dǎo)致空指針 是我用的版本的bug SR2版本已經(jīng)解決
exchange.getAttributes().put("original_response_content_type", headers.getContentType());
HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);
response.getHeaders().putAll(filteredResponseHeaders);
HttpStatus status = HttpStatus.resolve(res.status().code());
if (status != null) {
response.setStatusCode(status);
} else if (response instanceof AbstractServerHttpResponse) {
// https://jira.spring.io/browse/SPR-16748
((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());
} else {
throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());
}
// Defer committing the response until all route filters have run
// Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
}).then(chain.filter(exchange));
}
}
當(dāng)這步執(zhí)行完之后,可以理解為先前的NettyWriteResponseFilter 的then()開(kāi)始執(zhí)行,最終返回請(qǐng)求結(jié)果。至此spring cloud gateway 的啟動(dòng)流程和訪(fǎng)問(wèn)流程就結(jié)束了。