中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

如何快速找到做網(wǎng)站的客戶站長(zhǎng)素材網(wǎng)

如何快速找到做網(wǎng)站的客戶,站長(zhǎng)素材網(wǎng),網(wǎng)購(gòu)哪個(gè)平臺(tái)最靠譜,和什么人合作做游戲視頻網(wǎng)站文章目錄 源碼總流程圖說(shuō)明GateWayAutoConfigurationDispatcherHandlergetHandler()handleRequestWith()RouteToRequestUrlFilterReactiveLoadBalancerClientFilterNettyRoutingFilter 補(bǔ)充知識(shí)適配器模式 詳細(xì)流程圖 源碼總流程圖 在線總流程圖 說(shuō)明 Gateway的版本使用的是…

文章目錄

    • 源碼總流程圖
    • 說(shuō)明
    • GateWayAutoConfiguration
    • DispatcherHandler
    • getHandler()
    • handleRequestWith()
      • RouteToRequestUrlFilter
      • ReactiveLoadBalancerClientFilter
      • NettyRoutingFilter
    • 補(bǔ)充知識(shí)
      • 適配器模式
    • 詳細(xì)流程圖

源碼總流程圖

在線總流程圖
在這里插入圖片描述



說(shuō)明

Gateway的版本使用的是4.0.0

Gateway的實(shí)現(xiàn)是基于WebFlux 、Reactor 、Netty



Gateway微服務(wù)的yml配置如下

  • Gateway的訪問(wèn)端口為8888
  • id為order_route的路由 uri為lb://mall-order
  • 為mall-order這個(gè)微服務(wù)定義了一個(gè)path路徑的predicate斷言;定義了三個(gè)filter
server:port: 8888
spring:application:name: mall-gateway#配置nacos注冊(cè)中心地址cloud:nacos:discovery:server-addr: nacos.mall.com:8848username: nacospassword: nacosgateway:#設(shè)置路由:路由id、路由到微服務(wù)的uri、斷言routes:- id: user_route   #路由ID,全局唯一uri: lb://mall-user  #lb 整合負(fù)載均衡器ribbon,loadbalancerpredicates:- Path=/user/**   # 斷言,路徑相匹配的進(jìn)行路由- id: order_route  #路由ID,全局唯一# 測(cè)試 http://localhost:8888/order/findOrderByUserId/1uri: lb://mall-order  #lb 整合負(fù)載均衡器loadbalancerpredicates:- Path=/order/**   # 斷言,路徑相匹配的進(jìn)行路由#配置過(guò)濾器工廠filters:- AddRequestHeader=X-Request-color, red  #添加請(qǐng)求頭- AddRequestParameter=color, blue  # 添加請(qǐng)求參數(shù)- CheckAuth=hushang,#自定義過(guò)濾器工廠



Gateway的工作原理就是下面這一張圖

在這里插入圖片描述



在開(kāi)始看Gateway的源碼之前,我們回憶一下SpringMVC的實(shí)現(xiàn)原理:

  1. DispatchServlet#doDispatch作為Springmvc的入口
  2. HandlerMapper 路由匹配 —> 找到Handler
  3. 通過(guò)handler 找的適配的 HandlerAdapter
  4. HandlerAdapter#handle方法執(zhí)行



而在Gateway的源碼中:

  • DispatcherHandler#handle作為入口
  • HandlerMapping 路由匹配 --> 斷言predicate匹配 RoutePredicateHandlerMapping#getHandlerInternal,找到路由Route對(duì)象
  • 返回FilteringWebHandler
  • HandlerAdapter 適配器 SimpleHandlerAdapter#handle 處理WebHandler
  • 進(jìn)入到org.springframework.cloud.gateway.handler.FilteringWebHandler#handle —> filterChain處理



Flux和Mono的概念

Reactor學(xué)習(xí)文檔

Flux:

在這里插入圖片描述



Mono:

在這里插入圖片描述



GateWayAutoConfiguration

在這里插入圖片描述



在GatewayAutoConfiguration自動(dòng)配置類中,它配置了很多bean對(duì)象,常見(jiàn)的就比如:

// 保存我們配置文件中關(guān)于網(wǎng)關(guān)路由相關(guān)的所有配置
// GatewayProperties保存了List<RouteDefinition>
// 而RouteDefinition就是每一個(gè)路由對(duì)象,保存了id、uri、斷言集合List<PredicateDefinition>、Filter集合List<FilterDefinition>
@Bean
public GatewayProperties gatewayProperties() {return new GatewayProperties();
}// Path路徑匹配的斷言工廠,斷言相關(guān)的bean都是以RoutePredicateFactory結(jié)尾
@Bean
@ConditionalOnEnabledPredicate
public PathRoutePredicateFactory pathRoutePredicateFactory() {return new PathRoutePredicateFactory();
}// 添加請(qǐng)求頭的Filter,一般都是以GatewayFilterFactory
@Bean
@ConditionalOnEnabledFilter
public AddRequestHeaderGatewayFilterFactory addRequestHeaderGatewayFilterFactory() {return new AddRequestHeaderGatewayFilterFactory();
}// 全局過(guò)濾器,把我們?cè)L問(wèn)網(wǎng)關(guān)的url轉(zhuǎn)換為路由中配置的uri
// http://localhost:8888/order/findOrderByUserId/1  --->  lb://mall-order/order/findOrderByUserId/1
@Bean
@ConditionalOnEnabledGlobalFilter
public RouteToRequestUrlFilter routeToRequestUrlFilter() {return new RouteToRequestUrlFilter();
}



GateWayAutoConfiguration配置的主要bean

類名說(shuō)明
GatewayPropertiesgateway屬性配置類
PropertiesRouteDefinitionLocator操作GatewayProperties對(duì)象,返回Flux<RouteDefinition>
RouteDefinitionRouteLocator將RouteDefinition轉(zhuǎn)換為Route
RoutePredicateHandlerMappingGateway的HandlerMapping,匹配請(qǐng)求對(duì)應(yīng)的Route,返回FilteringWebHandler
XXXRoutePredicateFactory路由斷言工廠的bean
XXXGatewayFilterFactory局部Filter
GlobalFilter實(shí)現(xiàn)類全局Filter



DispatcherHandler

DispatcherHandler#handle作為我們查看Gateway源碼的入口

  • 請(qǐng)求request和響應(yīng)response實(shí)例會(huì)被封裝為ServerWebExchange
  • 核心方法就是return語(yǔ)句
@Override
public Mono<Void> handle(ServerWebExchange exchange) {if (this.handlerMappings == null) {return createNotFoundError();}if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {return handlePreFlight(exchange);}return Flux.fromIterable(this.handlerMappings) // 遍歷所有的HandlerMapper.concatMap(mapping -> mapping.getHandler(exchange)) // 調(diào)用每一個(gè)HandlerMapper,能否找到Handler.next() // 繼續(xù)遍歷下一個(gè)HandlerMapper.switchIfEmpty(createNotFoundError()) // 如果HandlerMapper遍歷完后都沒(méi)有Handler,那么要拋異常了.onErrorResume(ex -> handleDispatchError(exchange, ex)).flatMap(handler -> handleRequestWith(exchange, handler)); // 如果找到Handler,那就去通過(guò)HandlerAdapter去調(diào)用Handler
}



fromIterable()方法的作用就是就是遍歷Gateway所有的HandlerMapper,我們這里肯定最終是使用的RoutePredicateHandlerMapping這個(gè)路由斷言的

在這里插入圖片描述

我們接下來(lái)繼續(xù)往下,遍歷各個(gè)HandlerMapper,并調(diào)用mapping.getHandler(exchange)方法,這里最終會(huì)調(diào)用至RoutePredicateHandlerMapping類的getHandlerInternal()方法中,經(jīng)過(guò)斷言匹配后,返回一個(gè)FilteringWebHandler對(duì)象。該方法接下來(lái)會(huì)詳細(xì)介紹。



中間這幾行其實(shí)主要就是如果我當(dāng)前往Gateway的請(qǐng)求,通過(guò)路由斷言沒(méi)有匹配上,那么就會(huì)拋異常

.next()
.switchIfEmpty(createNotFoundError())
.onErrorResume(ex -> handleDispatchError(exchange, ex))



經(jīng)過(guò)路由斷言匹配,得到一個(gè)WebHandler對(duì)象之后,會(huì)執(zhí)行handleRequestWith(exchange, handler)方法,在該方法中會(huì)找一個(gè)與WebHandler匹配的HandlerAdapter來(lái)適配WebHandler對(duì)象,最終去調(diào)用WebHandler的



getHandler()

通過(guò)DispatcherHandler#handle方法中的.concatMap(mapping -> mapping.getHandler(exchange)) 這一行代碼

進(jìn)入到了AbstractHandlerMapping#getHandler

  • 遍歷我們yml配置文件中所有定義的路由

  • 根據(jù)我們路由定義的斷言Predicate規(guī)則去調(diào)用對(duì)應(yīng)的斷言工廠

  • 將匹配成功的路由保存至exchange對(duì)象中

    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
    exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR, routeId);

  • 斷言匹配成功就返回一個(gè)WebHandler接口的實(shí)現(xiàn)類FilteringWebHandler對(duì)象

public Mono<Object> getHandler(ServerWebExchange exchange) {// 從這里我們就可以發(fā)現(xiàn),通過(guò)getHandlerInternal(exchange)方法就能找Handler,之后的.map()方法中就直接return handler;return getHandlerInternal(exchange).map(handler -> {if (logger.isDebugEnabled()) {logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);}ServerHttpRequest request = exchange.getRequest();// 正常情況下這個(gè)if都不會(huì)進(jìn)入if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {CorsConfiguration config = (this.corsConfigurationSource != null ?this.corsConfigurationSource.getCorsConfiguration(exchange) : null);CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);config = (config != null ? config.combine(handlerConfig) : handlerConfig);if (config != null) {config.validateAllowCredentials();}if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {return NO_OP_HANDLER;}}// 直接返回handlerreturn handler;});
}





我們這里就直接進(jìn)入到RoutePredicateHandlerMapping類中

在這里插入圖片描述

RoutePredicateHandlerMapping#getHandlerInternal的詳細(xì)代碼如下

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {if (this.managementPortType == DIFFERENT && this.managementPort != null&& exchange.getRequest().getURI().getPort() == this.managementPort) {return Mono.empty();}exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());return Mono.deferContextual(contextView -> {exchange.getAttributes().put(GATEWAY_REACTOR_CONTEXT_ATTR, contextView);// 核心方法是lookupRoute(exchange),這里會(huì)去進(jìn)行路由的校驗(yàn),根據(jù)我們配置文件中定義的路由斷言規(guī)則進(jìn)行校驗(yàn)return lookupRoute(exchange).flatMap((Function<Route, Mono<?>>) r -> {// 下面幾行代碼就是操作exchange的屬性// 上方的lookupRoute()方法中會(huì)添加GATEWAY_PREDICATE_ROUTE_ATTR,這里就進(jìn)行移除exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);// 把當(dāng)前路由對(duì)象添加進(jìn)exchange對(duì)象中,之后的流程還會(huì)用到我們的路由對(duì)象exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);// 路由匹配成功,就直接返回WebHandler對(duì)象return Mono.just(webHandler);}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {// 當(dāng)前請(qǐng)求沒(méi)有任何一個(gè)路由匹配上的處理流程exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);if (logger.isTraceEnabled()) {logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");}})));});
}





再進(jìn)入到RoutePredicateHandlerMapping#lookupRoute方法中

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {// 獲取到我們yml配置文件中所有定義的路由,并進(jìn)行遍歷return this.routeLocator.getRoutes().concatMap(route -> Mono.just(route).filterWhen(r -> {// 添加GATEWAY_PREDICATE_ROUTE_ATTRexchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());// 調(diào)用當(dāng)前路由對(duì)象中的斷言的apply()方法,apply()方法中又是一些異步的處理流程// 這里就會(huì)根據(jù)我們配置文件中為路由配置的各個(gè)斷言,去調(diào)用各個(gè)斷言對(duì)象return r.getPredicate().apply(exchange);}).doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e)).onErrorResume(e -> Mono.empty())).next()// TODO: error handling.map(route -> {if (logger.isDebugEnabled()) {logger.debug("Route matched: " + route.getId());}validateRoute(route, exchange);return route;});
}

我當(dāng)前gateway的配置文件中定義了兩個(gè)路由

spring:cloud:gateway:#設(shè)置路由:路由id、路由到微服務(wù)的uri、斷言routes:- id: user_route   #路由ID,全局唯一uri: lb://mall-user  #lb 整合負(fù)載均衡器ribbon,loadbalancerpredicates:- Path=/user/**   # 斷言,路徑相匹配的進(jìn)行路由- id: order_route  #路由ID,全局唯一# 測(cè)試 http://localhost:8888/order/findOrderByUserId/1uri: lb://mall-order  #lb 整合負(fù)載均衡器loadbalancerpredicates:- Path=/order/**   # 斷言,路徑相匹配的進(jìn)行路由

所以上面的方法會(huì)執(zhí)行兩次

在這里插入圖片描述

在這里插入圖片描述

因?yàn)?code>return r.getPredicate().apply(exchange);又是一些異步調(diào)用,但我們從方法名就能看出來(lái),這里根據(jù)我們yml配置文件中路由定義的斷言去調(diào)用對(duì)應(yīng)的斷言對(duì)象。這就是各個(gè)斷言工廠具體的實(shí)現(xiàn)了,接下來(lái)就以Path路徑匹配的斷言工廠來(lái)舉例

class DefaultAsyncPredicate<T> implements AsyncPredicate<T> {private final Predicate<T> delegate;@Overridepublic Publisher<Boolean> apply(T t) { // 調(diào)用各個(gè)Predicate對(duì)象的test()方法return Mono.just(delegate.test(t));}//...
}





所以我們現(xiàn)在就直接去看path路徑匹配的斷言類PathRoutePredicateFactory

@Override
public Predicate<ServerWebExchange> apply(Config config) {final ArrayList<PathPattern> pathPatterns = new ArrayList<>();synchronized (this.pathPatternParser) {pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchTrailingSlash());config.getPatterns().forEach(pattern -> {PathPattern pathPattern = this.pathPatternParser.parse(pattern);pathPatterns.add(pathPattern);});}return new GatewayPredicate() {// 會(huì)進(jìn)入到test()方法中@Overridepublic boolean test(ServerWebExchange exchange) {// 當(dāng)前請(qǐng)求的uri路徑  /order/findOrderByUserId/1PathContainer path = parsePath(exchange.getRequest().getURI().getRawPath());PathPattern match = null;for (int i = 0; i < pathPatterns.size(); i++) {// yml配置文件中的配置項(xiàng)  /order/**PathPattern pathPattern = pathPatterns.get(i);// 如果path匹配成功,那么match對(duì)象就不為nullif (pathPattern.matches(path)) {match = pathPattern;break;}}// 如果path匹配成功,那么match對(duì)象就不為null  。匹配成功的處理邏輯if (match != null) {traceMatch("Pattern", match.getPatternString(), path, true);PathMatchInfo pathMatchInfo = match.matchAndExtract(path);putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());//  match.getPatternString() 為   /order/**exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ATTR, match.getPatternString());String routeId = (String) exchange.getAttributes().get(GATEWAY_PREDICATE_ROUTE_ATTR);// 保存當(dāng)前路由idif (routeId != null) {exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR, routeId);}return true;}// path匹配不成,返回falseelse {traceMatch("Pattern", config.getPatterns(), path, false);return false;}}@Overridepublic Object getConfig() {return config;}@Overridepublic String toString() {return String.format("Paths: %s, match trailing slash: %b", config.getPatterns(),config.isMatchTrailingSlash());}};
}



handleRequestWith()

// DispatcherHandler#handleRequestWith
private Mono<Void> handleRequestWith(ServerWebExchange exchange, Object handler) {if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {return Mono.empty();  // CORS rejection}if (this.handlerAdapters != null) {// 遍歷所有的HandlerAdapterfor (HandlerAdapter adapter : this.handlerAdapters) {// 找能處理WebHandler類型的HandlerAdapter , 最終找到SimpleHandlerAdapterif (adapter.supports(handler)) {return adapter.handle(exchange, handler).flatMap(result -> handleResult(exchange, result));}}}return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

如下圖所示,找到SimpleHandlerAdapter這個(gè)

在這里插入圖片描述



SimpleHandlerAdapter的詳細(xì)代碼如下所示

public class SimpleHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return WebHandler.class.isAssignableFrom(handler.getClass());}@Overridepublic Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {// 強(qiáng)轉(zhuǎn)WebHandler webHandler = (WebHandler) handler;// getHandler()方法返回了一個(gè)FilteringWebHandler對(duì)象,這里就調(diào)用它的handle()方法Mono<Void> mono = webHandler.handle(exchange);// 返回一個(gè)空對(duì)象return mono.then(Mono.empty());}}



FilteringWebHandler#handle方法

@Override
public Mono<Void> handle(ServerWebExchange exchange) {// getHandler()方法中存入了Route路由對(duì)象,這里取出來(lái),該對(duì)象保存著我們yml配置文件中的配置Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);// 取出我們yml配置文件中 該路由的局部Filter,我這里有三個(gè),一個(gè)添加請(qǐng)求頭、一個(gè)添加請(qǐng)求參數(shù)、一個(gè)自定義的List<GatewayFilter> gatewayFilters = route.getFilters();// 全局FilterList<GatewayFilter> combined = new ArrayList<>(this.globalFilters);// 將局部Filter和全局Filter存入一個(gè)集合中combined.addAll(gatewayFilters);// 排序AnnotationAwareOrderComparator.sort(combined);if (logger.isDebugEnabled()) {logger.debug("Sorted gatewayFilterFactories: " + combined);}// 調(diào)用各自的filter()方法return new DefaultGatewayFilterChain(combined).filter(exchange);
}



在這里插入圖片描述

[GatewayFilterAdapter{RemoveCachedBodyFilter@5cfed0ba}, order = -2147483648]"
[GatewayFilterAdapter{AdaptCachedBodyGlobalFilter@22a6d75c}, order = -2147482648]"
[GatewayFilterAdapter{NettyWriteResponseFilter@691567ea}, order = -1]"
[GatewayFilterAdapter{ForwardPathFilter@28be7fec}, order = 0]"
// 三個(gè)局部Filter
[[AddRequestHeader X-Request-color = 'red'], order = 1]"
[[AddRequestParameter color = 'blue'], order = 2]"
[com.tuling.mall.gateway.filter.CheckAuthGatewayFilterFactory$$Lambda$980/0x0000014b3c649390@54f513cb, order = 3]"
// 路由轉(zhuǎn)換 把http://localhost:8888/order/findOrderByUserId/1  --->  lb://mall-order/order/findOrderByUserId/1
[GatewayFilterAdapter{RouteToRequestUrlFilter@5c8d58ed}, order = 10000]"
// 根據(jù)lb://前綴過(guò)濾處理,使用serviceId選擇一個(gè)服務(wù)實(shí)例,從而實(shí)現(xiàn)負(fù)載均衡
[GatewayFilterAdapter{ReactiveLoadBalancerClientFilter@437ed416}, order = 10150]"
[GatewayFilterAdapter{LoadBalancerServiceInstanceCookieFilter@11f23038}, order = 10151]"
[GatewayFilterAdapter{WebsocketRoutingFilter@26f0141}, order = 2147483646]"
// 發(fā)送netty 請(qǐng)求
[GatewayFilterAdapter{NettyRoutingFilter@de77146}, order = 2147483647]"
[GatewayFilterAdapter{ForwardRoutingFilter@6a567f7b}, order = 2147483647]"



接下來(lái)就挑幾個(gè)重要的全局GlobalFilter來(lái)分析

RouteToRequestUrlFilter

路由轉(zhuǎn)換 把http://localhost:8888/order/findOrderByUserId/1?color=blue —> lb://mall-order/order/findOrderByUserId/1?color=blue

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 從exchange中取路由Route對(duì)象Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);if (route == null) {return chain.filter(exchange);}log.trace("RouteToRequestUrlFilter start");// 取當(dāng)前請(qǐng)求uri : http://localhost:8888/order/findOrderByUserId/1?color=blueURI uri = exchange.getRequest().getURI();boolean encoded = containsEncodedParts(uri);// 路由對(duì)象中保存的uri,也就是我們?cè)趛ml文件中配置的值:   lb://mall-orderURI routeUri = route.getUri();if (hasAnotherScheme(routeUri)) {exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());routeUri = URI.create(routeUri.getSchemeSpecificPart());}// 如果我們?cè)趛ml文件中配置的uri,即不是lb開(kāi)頭并且host還為null,那么就拋異常if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) {throw new IllegalStateException("Invalid host: " + routeUri.toString());}// 轉(zhuǎn)換結(jié)果為:  lb://mall-order/order/findOrderByUserId/1?color=blueURI mergedUrl = UriComponentsBuilder.fromUri(uri).scheme(routeUri.getScheme()).host(routeUri.getHost()).port(routeUri.getPort()).build(encoded).toUri();// 存入exchange中,之后的LoadBalancer全局Filter中會(huì)用到exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);return chain.filter(exchange);
}



ReactiveLoadBalancerClientFilter

解析lb://服務(wù)名,去服務(wù)注冊(cè)中心獲取服務(wù)實(shí)例instance,并通過(guò)負(fù)載均衡算法選擇一個(gè)具體的instance

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 此時(shí)的url是這個(gè)樣子:   lb://mall-order/order/findOrderByUserId/1?color=blueURI 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);}addOriginalRequestUrl(exchange, url);if (log.isTraceEnabled()) {log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);}// 再獲取一遍:lb://mall-order/order/findOrderByUserId/1?color=blueURI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);// 就是服務(wù)名:    mall-orderString serviceId = requestUri.getHost();Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator.getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),RequestDataContext.class, ResponseData.class, ServiceInstance.class);// 請(qǐng)求信息 封裝成一個(gè)對(duì)象DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(new RequestData(exchange.getRequest()), getHint(serviceId)));// 調(diào)用choose()方法return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {// 服務(wù)注冊(cè)中心的響應(yīng)response,獲取server實(shí)例對(duì)象ServiceInstance retrievedInstance = response.getServer();// 值為http://localhost:8888/order/findOrderByUserId/1?color=blueURI uri = exchange.getRequest().getURI();String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";if (schemePrefix != null) {overrideScheme = url.getScheme();}// 服務(wù)實(shí)例DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance,overrideScheme);// 最終通過(guò)上面的服務(wù)實(shí)例,修改之后的請(qǐng)求url為:http://192.168.236.173:8020/order/findOrderByUserId/1?color=blueURI requestUrl = reconstructURI(serviceInstance, uri);if (log.isTraceEnabled()) {log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);}// 存入exchange對(duì)象中,之后netty發(fā)送請(qǐng)求會(huì)用到該urlexchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response));}).then(chain.filter(exchange)).doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(CompletionContext.Status.FAILED, throwable, lbRequest,exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR))))).doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(CompletionContext.Status.SUCCESS, lbRequest,exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR),new ResponseData(exchange.getResponse(), new RequestData(exchange.getRequest()))))));
}// 進(jìn)入到choose()方法中
private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId,Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {ReactorLoadBalancer<ServiceInstance> loadBalancer = this.clientFactory.getInstance(serviceId,ReactorServiceInstanceLoadBalancer.class);if (loadBalancer == null) {throw new NotFoundException("No loadbalancer available for " + serviceId);}supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));// 調(diào)用ReactorLoadBalancer對(duì)象的choose()方法return loadBalancer.choose(lbRequest);
}



NettyRoutingFilter

發(fā)送netty請(qǐng)求

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 經(jīng)過(guò)負(fù)載均衡之后的請(qǐng)求url,具體的下游服務(wù)請(qǐng)求地址// http://192.168.236.173:8020/order/findOrderByUserId/1?color=blueURI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);// scheme為httpString scheme = requestUrl.getScheme();if (isAlreadyRouted(exchange) || (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme))) {return chain.filter(exchange);}setAlreadyRouted(exchange);ServerHttpRequest request = exchange.getRequest();// GET 請(qǐng)求final HttpMethod method = HttpMethod.valueOf(request.getMethod().name());// url為 http://192.168.236.173:8020/order/findOrderByUserId/1?color=bluefinal String url = requestUrl.toASCIIString();// 請(qǐng)求頭HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();filtered.forEach(httpHeaders::set);boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);// 路由對(duì)象Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange).headers(headers -> {headers.add(httpHeaders);// Will either be set below, or later by Nettyheaders.remove(HttpHeaders.HOST);if (preserveHost) {String host = request.getHeaders().getFirst(HttpHeaders.HOST);headers.add(HttpHeaders.HOST, host);}// 發(fā)送請(qǐng)求}).request(method).uri(url).send((req, nettyOutbound) -> {if (log.isTraceEnabled()) {nettyOutbound.withConnection(connection -> log.trace(...);}return nettyOutbound.send(request.getBody().map(this::getByteBuf));}).responseConnection((res, connection) -> {// Defer committing the response until all route filters have run// Put client response as ServerWebExchange attribute and write// response later NettyWriteResponseFilterexchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection);ServerHttpResponse response = exchange.getResponse();// put headers and status so filters can modify the responseHttpHeaders headers = new HttpHeaders();res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));String contentTypeValue = headers.getFirst(HttpHeaders.CONTENT_TYPE);if (StringUtils.hasLength(contentTypeValue)) {exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, contentTypeValue);}setResponseStatus(res, response);// make sure headers filters run after setting status so it is// available in responseHttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(getHeadersFilters(), headers, exchange,Type.RESPONSE);if (!filteredResponseHeaders.containsKey(HttpHeaders.TRANSFER_ENCODING)&& filteredResponseHeaders.containsKey(HttpHeaders.CONTENT_LENGTH)) {// It is not valid to have both the transfer-encoding header and// the content-length header.// Remove the transfer-encoding header in the response if the// content-length header is present.response.getHeaders().remove(HttpHeaders.TRANSFER_ENCODING);}exchange.getAttributes().put(CLIENT_RESPONSE_HEADER_NAMES, filteredResponseHeaders.keySet());response.getHeaders().addAll(filteredResponseHeaders);return Mono.just(res);});Duration responseTimeout = getResponseTimeout(route);if (responseTimeout != null) {responseFlux = responseFlux.timeout(responseTimeout,Mono.error(new TimeoutException("Response took longer than timeout: " + responseTimeout))).onErrorMap(TimeoutException.class,th -> new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, th.getMessage(), th));}return responseFlux.then(chain.filter(exchange));
}



補(bǔ)充知識(shí)

適配器模式

FilteringWebHandler#handle方法中,先獲取路由的局部Filter,在創(chuàng)建一個(gè)集合存放全局Filter,在把局部Filter和全局Filter放在一起。這里就有一個(gè)問(wèn)題:

局部Filter的類型是GatewayFilter,而全局Filter的類型是GlobalFilter,它們是怎么通過(guò)下面這種方式存放在一個(gè)集合中的嘞?

// 局部Filter
List<GatewayFilter> gatewayFilters = route.getFilters();
// 全局Filter
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
// 將局部Filter和全局Filter存入一個(gè)集合中
combined.addAll(gatewayFilters);



這里就用到了適配器模式,具體實(shí)現(xiàn)步驟是:

  • 創(chuàng)建一個(gè)GatewayFilterAdapter類,實(shí)現(xiàn) GatewayFilter接口
  • GatewayFilterAdapter類中定義一個(gè)GlobalFilter屬性,構(gòu)造方法中傳GlobalFilter類型的對(duì)象賦值給該屬性
  • 實(shí)現(xiàn)GatewayFilter接口的filter()方法,在filter()方法中調(diào)用全局Filter的filter()方法
private static class GatewayFilterAdapter implements GatewayFilter {private final GlobalFilter delegate;GatewayFilterAdapter(GlobalFilter delegate) {this.delegate = delegate;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return this.delegate.filter(exchange, chain);}
}



遍歷List<GlobalFilter> globalFilters全局Filter,分別存入GatewayFilterAdapter對(duì)象中

List<GatewayFilterAdapter> ----> List<GatewayFilter> globalFilters集合

@Override
public Mono<Void> handle(ServerWebExchange exchange) {Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);// 局部FilterList<GatewayFilter> gatewayFilters = route.getFilters();// 全局Filter,這樣就把全局GlobalFilter變?yōu)榱薌atewayFilter類型了List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);// 存入一個(gè)集合中combined.addAll(gatewayFilters);AnnotationAwareOrderComparator.sort(combined);// 調(diào)用各自的filter()方法return new DefaultGatewayFilterChain(combined).filter(exchange);
}



詳細(xì)流程圖

在這里插入圖片描述

http://www.risenshineclean.com/news/7995.html

相關(guān)文章:

  • 用wordpress做外貿(mào)網(wǎng)站b站推廣網(wǎng)站2024年
  • 企業(yè)對(duì)電子商務(wù)網(wǎng)站的建設(shè)網(wǎng)頁(yè)設(shè)計(jì)制作網(wǎng)站代碼
  • 做動(dòng)圖的網(wǎng)站在哪里推廣自己的產(chǎn)品
  • 網(wǎng)站搭建素材百度總部電話
  • 網(wǎng)站建設(shè)叫什么軟件網(wǎng)絡(luò)營(yíng)銷方式有哪些
  • 境外公司在國(guó)內(nèi)建網(wǎng)站黑馬it培訓(xùn)班出來(lái)現(xiàn)狀
  • 音樂(lè)網(wǎng)站開(kāi)發(fā)畢業(yè)論文創(chuàng)建網(wǎng)站需要多少資金
  • 網(wǎng)站建設(shè)初步認(rèn)識(shí)的實(shí)訓(xùn)體會(huì)行業(yè)網(wǎng)站有哪些平臺(tái)
  • 中山制作網(wǎng)站的公司西安網(wǎng)站推廣慧創(chuàng)科技
  • 互聯(lián)網(wǎng)下的網(wǎng)絡(luò)營(yíng)銷前端seo是什么意思
  • 網(wǎng)站建設(shè)營(yíng)銷方案整站外包優(yōu)化公司
  • 泉州北京網(wǎng)站建設(shè)如何制作app軟件
  • phpcms學(xué)校網(wǎng)站模板如何制作微信小程序店鋪
  • wordpress 社交分享肇慶seo排名外包
  • 網(wǎng)站倒計(jì)時(shí)代碼資源企業(yè)網(wǎng)站排名優(yōu)化價(jià)格
  • html制作網(wǎng)站的步驟網(wǎng)絡(luò)服務(wù)包括
  • 企業(yè)域名是什么網(wǎng)站seo關(guān)鍵詞設(shè)置
  • 網(wǎng)站設(shè)計(jì)營(yíng)銷網(wǎng)站出租三級(jí)域名費(fèi)用
  • 做視頻網(wǎng)站視頻的軟件企業(yè)營(yíng)銷培訓(xùn)課程
  • 女性時(shí)尚網(wǎng)站源碼客戶關(guān)系管理
  • 有沒(méi)有免費(fèi)的微網(wǎng)站視頻營(yíng)銷模式有哪些
  • 昭通網(wǎng)站建設(shè)如何提高網(wǎng)站排名的方法
  • 二手站網(wǎng)站怎做優(yōu)化課程體系
  • 招聘 負(fù)責(zé)網(wǎng)站開(kāi)發(fā)網(wǎng)絡(luò)營(yíng)銷有什么方式
  • 網(wǎng)站做cdn百度網(wǎng)頁(yè)版入口
  • 網(wǎng)站信息發(fā)布制度建設(shè)seo網(wǎng)站優(yōu)化排名
  • 建網(wǎng)站哪便宜百度網(wǎng)站提交入口網(wǎng)址
  • 網(wǎng)頁(yè)跟網(wǎng)站的區(qū)別百度seo2022
  • 開(kāi)發(fā)app的注意事項(xiàng)seo代理計(jì)費(fèi)系統(tǒng)
  • 兩耳清風(fēng)怎么做網(wǎng)站南京網(wǎng)絡(luò)優(yōu)化培訓(xùn)