gateway - 啓動

咱們從spring.factories開始,主要是GatewayAutoConfiguration,這裏主要加載CompositeRouteDefinitionLocator、RouteDefinitionRouteLocator、FilteringWebHandler、RoutePredicateHandlerMapping、RouteRefreshListener、CachingRouteLocator等。
RouteLocator和RouteDefinitionLocator的做用在上一篇已經提過了,FilteringWebHandler、RoutePredicateHandlerMapping這兩個等調用的時候講,這邊先知道他們會在這裏加載。咱們主要看看RouteRefreshListener和CachingRouteLocator。java

RouteRefreshListener

RouteRefreshListener實現了ApplicationListener接口,因此他會調用onApplicationEvent方法,在符合某些條件下,會調用reset方法,這個思路和zuul是同樣的。因此動態的刷新也能夠調用他的事件來觸發。spring

public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ContextRefreshedEvent
            || event instanceof RefreshScopeRefreshedEvent
            || event instanceof InstanceRegisteredEvent) {
        reset();
    }
    else if (event instanceof ParentHeartbeatEvent) {
        ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
    else if (event instanceof HeartbeatEvent) {
        HeartbeatEvent e = (HeartbeatEvent) event;
        resetIfNeeded(e.getValue());
    }
}

咱們看看reset方法,他其實就是發佈了一個RefreshRoutesEvent事件。segmentfault

private void reset() {
    this.publisher.publishEvent(new RefreshRoutesEvent(this));
}

CachingRouteLocator

CachingRouteLocator就是用來接收RefreshRoutesEvent事件的,他實現了ApplicationListener<RefreshRoutesEvent>接口。咱們看看他的onApplicationEvent方法。app

public void onApplicationEvent(RefreshRoutesEvent event) {
    try {
        fetch().collect(Collectors.toList()).subscribe(list -> Flux.fromIterable(list)
                .materialize().collect(Collectors.toList()).subscribe(signals -> {
                    applicationEventPublisher
                            .publishEvent(new RefreshRoutesResultEvent(this));
                    cache.put(CACHE_KEY, signals);
                }, throwable -> handleRefreshError(throwable)));
    }
    catch (Throwable e) {
        handleRefreshError(e);
    }
}

他先會調用fetch方法,這裏實際上就是調用CompositeRouteLocator#getRoutes,最後再調用RouteDefinitionRouteLocator#getRoutes。async

private Flux<Route> fetch() {
    return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
}

RouteDefinitionRouteLocator#getRoutes

這個方法能夠看到他是獲取RouteDefinition的集合,而後再調用convertToRoute方法,在這個方法裏,把RouteDefinition轉爲Route。ide

@Override
public Flux<Route> getRoutes() {
    Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
            .map(this::convertToRoute);

    // 其餘略
}

RouteDefinitionRouteLocator#convertToRoute

在這裏把RouteDefinition轉爲Route,主要是解析Predicate和GatewayFilter,咱們在上一篇已經知道了他會經過工廠類來處理。combinePredicates方法就是處理Predicate的,getFilters是處理Filter的。fetch

private Route convertToRoute(RouteDefinition routeDefinition) {
    AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
    List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);

    return Route.async(routeDefinition).asyncPredicate(predicate)
            .replaceFilters(gatewayFilters).build();
}

RouteDefinitionRouteLocator#combinePredicates

在這裏就是把RouteDefinition的predicate轉爲Route須要的Predicate。這裏首先會建立一個Predicate,而後再把剩餘的合併,造成了一個left、right的結構。結構圖在上一篇已經說過了。
lookup方法就是經過工廠類建立Predicate的地方。ui

private AsyncPredicate<ServerWebExchange> combinePredicates(
        RouteDefinition routeDefinition) {
    List<PredicateDefinition> predicates = routeDefinition.getPredicates();
    if (predicates == null || predicates.isEmpty()) {
        // this is a very rare case, but possible, just match all
        return AsyncPredicate.from(exchange -> true);
    }
    // 建立第一個Predicate
    AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
            predicates.get(0));
    // 把剩餘的進行合併
    for (PredicateDefinition andPredicate : predicates.subList(1,
            predicates.size())) {
        AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
                andPredicate);
        predicate = predicate.and(found);
    }

    return predicate;
}

RouteDefinitionRouteLocator#lookup

這個方法裏,首先先經過配置的名稱,獲取對應的RoutePredicateFactory,而後組裝config信息,最後經過factory.applyAsync建立Predicate。this

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

RouteDefinitionRouteLocator#getFilters

這個是處理Filter的地方,他主要是經過loadGatewayFilters方法來獲取對應的Filter。spa

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

    // TODO: support option to apply defaults after route specific filters?
    if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
        filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
                new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
    }

    if (!routeDefinition.getFilters().isEmpty()) {
        filters.addAll(loadGatewayFilters(routeDefinition.getId(),
                new ArrayList<>(routeDefinition.getFilters())));
    }

    AnnotationAwareOrderComparator.sort(filters);
    return filters;
}

RouteDefinitionRouteLocator#loadGatewayFilters

這個設計方式跟上面相似,也是經過配置信息的名稱,獲取對應的GatewayFilterFactory,而後封裝configuration信息,經過factory.apply建立一個Filter。

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

總體流程

image

相關文章
相關標籤/搜索