gateway隨筆

1,gateway配置類GatewayAutoConfiguration

  • 讀取配置文件(PropertiesRouteDefinitionLocator)
  • 加載過濾器工廠(XXXGatewayFilterFactory)
  • 加載路由斷言工廠(XXXRoutePredicateFactory)
  • 加載路由信息定位器類(RouteDefinitionRouteLocator)

注:配置中設置斷言和過濾器 必須使用首字母大寫车柠,eg.

routes:
        - id: r01
          order: 1
          #注:使用ld 注冊中心必須是同一分組瞄沙;引入spring-cloud-starter-loadbalancer 依賴患亿;服務名不能有"_"
          uri: lb://consumerService
          ####斷言 匹配規(guī)則
          predicates:
            - Path=/v1/**,/v2/**
            - Method=POST
            - Query=kk,v2.*
            - name: Query
              args:
                param: k1
                regexp: v1.*
          filters:
            ####去掉前綴
            - StripPrefix=1
            - name: Part

把各個斷言工廠類名去掉RoutePredicateFactory后的字符串作為key,類實例為value 保存到list中,在綁定值時通過配置中的斷言名稱name 去list進行獲取相應的斷言工廠厚脉,同理過濾器工廠也是同樣的處理习寸。

  • RouteDefinitionRouteLocator.java
public Flux<Route> getRoutes() {
        Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
                .map(this::convertToRoute);

        if (!gatewayProperties.isFailOnRouteDefinitionError()) {
            // instead of letting error bubble up, continue
            routes = routes.onErrorContinue((error, obj) -> {
                if (logger.isWarnEnabled()) {
                    logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
                            + " will be ignored. Definition has invalid configs, "
                            + error.getMessage());
                }
            });
        }

private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
            PredicateDefinition predicate) {
        RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
        if (factory == null) {
            throw new IllegalArgumentException(
                    "Unable to find RoutePredicateFactory with name "
                            + predicate.getName());
        }
        if (logger.isDebugEnabled()) {
            logger.debug("RouteDefinition " + route.getId() + " applying "
                    + predicate.getArgs() + " to " + predicate.getName());
        }

        // @formatter:off
        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

        return factory.applyAsync(config);
    }

//加載配置中的過濾器
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(
                        "Unable to find GatewayFilterFactory with name "
                                + definition.getName());
            }
            if (logger.isDebugEnabled()) {
                logger.debug("RouteDefinition " + id + " applying filter "
                        + definition.getArgs() + " to " + definition.getName());
            }

            // @formatter:off
            Object configuration = this.configurationService.with(factory)
                    .name(definition.getName())
                    .properties(definition.getArgs())
                    .eventFunction((bound, properties) -> new FilterArgsEvent(
                            // TODO: why explicit cast needed or java compile fails
                            RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
                    .bind();
            // @formatter:on

            // some filters require routeId
            // TODO: is there a better place to apply this?
            if (configuration instanceof HasRouteId) {
                HasRouteId hasRouteId = (HasRouteId) configuration;
                hasRouteId.setRouteId(id);
            }

            GatewayFilter gatewayFilter = factory.apply(configuration);
            if (gatewayFilter instanceof Ordered) {
                ordered.add(gatewayFilter);
            }
            else {
                ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
            }
        }

        return ordered;
    }

2,gateway 源碼執(zhí)行流程

gateway采用的是webFlux的響應式編程:

  • 請求分發(fā) DispatcherHandler
  • 請求映射 HandlerMapping
  • 請求適配 HanderAdaper
  • 請求處理 WebHander

DispatcherHandler.java

@Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        if (this.handlerMappings == null) {
            return createNotFoundError();
        }
        return Flux.fromIterable(this.handlerMappings)
                .concatMap(mapping -> mapping.getHandler(exchange))
                .next()
                .switchIfEmpty(createNotFoundError())
                .flatMap(handler -> invokeHandler(exchange, handler))
                .flatMap(result -> handleResult(exchange, result));
    }

在組裝過濾器時會把全局過濾器和局部過濾器組裝在一起,其中使用到適配器模式(GatewayFilterAdapter)。

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);
        // TODO: needed or cached?
        AnnotationAwareOrderComparator.sort(combined);

        if (logger.isDebugEnabled()) {
            logger.debug("Sorted gatewayFilterFactories: " + combined);
        }

        return new DefaultGatewayFilterChain(combined).filter(exchange);
    }

其中使用負載均衡(uri: lb://consumerService)也是通過過濾器實現(xiàn)的傻工。

LoadBalancerClientFilter.java

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        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);

        if (log.isTraceEnabled()) {
            log.trace("LoadBalancerClientFilter url before: " + url);
        }

        final ServiceInstance instance = choose(exchange);

        if (instance == null) {
            throw NotFoundException.create(properties.isUse404(),
                    "Unable to find instance for " + url.getHost());
        }

        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 = instance.isSecure() ? "https" : "http";
        if (schemePrefix != null) {
            overrideScheme = url.getScheme();
        }

        URI requestUrl = loadBalancer.reconstructURI(
                new DelegatingServiceInstance(instance, overrideScheme), uri);

        if (log.isTraceEnabled()) {
            log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
        }

        exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
        return chain.filter(exchange);
    }

參照:https://blog.csdn.net/qq_45076180/article/details/117112434

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末霞溪,一起剝皮案震驚了整個濱河市孵滞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸯匹,老刑警劉巖坊饶,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異殴蓬,居然都是意外死亡匿级,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門科雳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來根蟹,“玉大人,你說我怎么就攤上這事糟秘。” “怎么了球散?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵尿赚,是天一觀的道長。 經(jīng)常有香客問我蕉堰,道長凌净,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任屋讶,我火速辦了婚禮冰寻,結果婚禮上,老公的妹妹穿的比我還像新娘皿渗。我一直安慰自己斩芭,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布乐疆。 她就那樣靜靜地躺著划乖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挤土。 梳的紋絲不亂的頭發(fā)上琴庵,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音仰美,去河邊找鬼迷殿。 笑死,一個胖子當著我的面吹牛咖杂,可吹牛的內(nèi)容都是我干的庆寺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼翰苫,長吁一口氣:“原來是場噩夢啊……” “哼止邮!你這毒婦竟也來了这橙?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤导披,失蹤者是張志新(化名)和其女友劉穎屈扎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撩匕,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡鹰晨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了止毕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片模蜡。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖扁凛,靈堂內(nèi)的尸體忽然破棺而出忍疾,到底是詐尸還是另有隱情,我是刑警寧澤谨朝,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布卤妒,位于F島的核電站,受9級特大地震影響字币,放射性物質發(fā)生泄漏则披。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一洗出、第九天 我趴在偏房一處隱蔽的房頂上張望士复。 院中可真熱鬧,春花似錦翩活、人聲如沸阱洪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澄峰。三九已至,卻和暖如春辟犀,著一層夾襖步出監(jiān)牢的瞬間俏竞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工堂竟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留魂毁,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓出嘹,卻偏偏與公主長得像席楚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子税稼,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容