spring cloud gateway 作為新一代的微服務(wù)網(wǎng)關(guān)已經(jīng)發(fā)布了一段時(shí)間晶通,我從7月份開始使用到現(xiàn)在已經(jīng)4個(gè)月了撒璧。但是我一直處于一種只會(huì)使用洲胖,原理一知半解的水平竣况。我們小組作為公司微服務(wù)產(chǎn)品的實(shí)踐者扇丛,我自己作為組中一員完成了spring cloud gateway的開發(fā)愉镰,也解決了很多棘手的問題周拐,卻對(duì)它的原理和啟動(dòng)流程一知半解浑测,好幾次就是因?yàn)椴涣私馑膯?dòng)流程劫恒,導(dǎo)致開發(fā)受挫树叽,進(jìn)度緩慢∩婺伲現(xiàn)在正值閑時(shí)淹冰,正好看一下相關(guān)的源碼晒哄,理解他的啟動(dòng)流程购啄。本文基于spring cloud Finchley.RELEASE版本襟企,最新的SR2版本一些內(nèi)容有改變,但總體改變不大狮含。
首先是網(wǎng)關(guān)的包結(jié)構(gòu)
其中actuate中定義了一個(gè)叫GatewayControllerEndpoint的類顽悼,這個(gè)類提供一些對(duì)外的接口曼振,可以獲取網(wǎng)關(guān)的一些信息,比如路由的信息蔚龙,改變路由地址等等冰评。
config中定義了一些啟動(dòng)時(shí)去加載的類,配置路由信息和讀取你的配置文件就在這里完成木羹。
discovery中定義了注冊(cè)中心相關(guān)的內(nèi)容甲雅,包括注冊(cè)中心的路由等。
event定義了一些事件他們都繼承自ApplicationEvent坑填,對(duì)事件發(fā)布不了解的可以去看看spring的代碼抛人。
filter中定義了spring cloud gateway實(shí)現(xiàn)的一些過濾器。
handler中定義了很多Predicate相關(guān)的Factory
route就是我們路由的相關(guān)
support是工具包等脐瑰。
下面就是gateway啟動(dòng)流程的分析了
config包
網(wǎng)關(guān)啟動(dòng)第一步加載的就是去加載config包下的幾個(gè)類妖枚。
這幾個(gè)類就定義了網(wǎng)關(guān)需要加載的配置項(xiàng)。
在我第一次做網(wǎng)關(guān)開發(fā)的時(shí)候我引入了spring-boot-starter-web的依賴蚪黑,這樣是會(huì)報(bào)錯(cuò)的盅惜,因?yàn)間ateway是基于spring-webflux開發(fā)的中剩,他依賴的DispatcherHandler就和我們web里的DispatcherServlet一樣的功能忌穿。
這里的GatewayClassPathWarningAutoConfiguration這個(gè)類,就指明了我們需要什么不需要什么结啼,他加載于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ù)載均衡的過濾器實(shí)現(xiàn)的加載,他將LoadBalancerClientFilter 注入到了容器中属铁,這個(gè)過濾器后面再說眠寿。
@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)容焦蘑,我們大部分用到的過濾器盯拱,過濾器工廠都是在這里構(gòu)建的。包括之前的gatewayControllerEndpoint也是在這里注入容器中的例嘱。這個(gè)類的定義很長(zhǎng)狡逢,我就不再這里都放了,列舉幾個(gè)拼卵。
@Configuration
//開啟網(wǎng)關(guān)奢浑,不寫默認(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)部類就是初始化netty需要的東西雀彼。
}
//初始化了加載配置文件的對(duì)象壤蚜,建立route
@Bean
public GatewayProperties gatewayProperties() {
return new GatewayProperties();
}
//初始化請(qǐng)求轉(zhuǎn)發(fā) 過濾器
@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);
}
}
這里注意我們通過注冊(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è)完畢后,我們的配置文件就開始讀取了徊哑,
這兩個(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);
}
這里就定義了我們配置文件里的所有路由信息水泉,讀取完成后,接下來就要變成真正的路由信息了窒盐。
這里就要說一下 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è)類的一個(gè)屬性routeDefinitionLocator中已經(jīng)定義了我們的路由,只不過是代理對(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)存在了嗽交。通過他的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> 再通過convertToRoute轉(zhuǎn)換成路由對(duì)象的數(shù)組,封裝成Flux()至此夫壁,配置文件中讀取路由信息就結(jié)束了拾枣。
接下來我們來解釋通過注冊(cè)中心的方式接受的路由信息。這里由一個(gè)叫DiscoveryClientRouteDefinitionLocator的類來實(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è)配置是前面說過的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í)候,他通過discoveryClient轉(zhuǎn)換出了服務(wù)發(fā)現(xiàn)中心的服務(wù)路由
注意這里他沒有被轉(zhuǎn)換為Flux<Route>而是保留為Flux<RouteDefinition> 這是一個(gè)坑邑茄,我們前期很多時(shí)候去找Route發(fā)現(xiàn)根本就沒有從服務(wù)注冊(cè)中心拉下來的姨蝴,現(xiàn)在才知道,他壓根就沒去轉(zhuǎn)肺缕。
到這里左医,我們的路由信息就加載完畢了,網(wǎng)關(guān)也就啟動(dòng)完成了搓谆,之后就是發(fā)送請(qǐng)求過濾器發(fā)功的時(shí)候了炒辉。
我們第一個(gè)關(guān)注的類就是DispatcherHandler,這個(gè)類提供的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()方法黔寇,具體的我也沒看明白,大概就是封裝了這些Mapping進(jìn)入之后的過濾鏈中
之后就到了FilteringWebHandler類斩萌,他的handler方法封裝了過濾器進(jìn)去
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//h獲取到當(dāng)前訪問的路由對(duì)象
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//獲取當(dāng)前已經(jīng)存在的 過濾器 也就是配置的默認(rèn)過濾器
List<GatewayFilter> gatewayFilters = route.getFilters();
//獲取全局過濾器
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);
}
這里的全局過濾器包括除了我標(biāo)記的兩個(gè)以外的所有過濾器缝裤,之后再介紹
最后按照order排序后的過濾器順序?yàn)?/p>
之后就真正的開始進(jìn)入過濾鏈了 排除掉我們自己實(shí)現(xiàn)的過濾器 第一個(gè)進(jìn)入的是AdaptCachedBodyGlobalFilter
他用來緩存我們的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ù)寫
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è)過濾器實(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í)行,也就是過濾鏈執(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é)果了 沒什么可說的霎苗。之后的過濾器我就不一個(gè)一個(gè)說了,講講比較重要的榛做。
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)是正確的訪問地址了厘擂。
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è)類不是很長(zhǎng) 我就都拷過來
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 和沒有被路由
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()開始執(zhí)行避凝,最終返回請(qǐng)求結(jié)果舞萄。至此spring cloud gateway 的啟動(dòng)流程和訪問流程就結(jié)束了。