咱們從spring.factories開始,主要是GatewayAutoConfiguration,這裏主要加載CompositeRouteDefinitionLocator、RouteDefinitionRouteLocator、FilteringWebHandler、RoutePredicateHandlerMapping、RouteRefreshListener、CachingRouteLocator等。
RouteLocator和RouteDefinitionLocator的做用在上一篇已經提過了,FilteringWebHandler、RoutePredicateHandlerMapping這兩個等調用的時候講,這邊先知道他們會在這裏加載。咱們主要看看RouteRefreshListener和CachingRouteLocator。java
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就是用來接收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); }
這個方法能夠看到他是獲取RouteDefinition的集合,而後再調用convertToRoute方法,在這個方法裏,把RouteDefinition轉爲Route。ide
@Override public Flux<Route> getRoutes() { Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions() .map(this::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(); }
在這裏就是把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; }
這個方法裏,首先先經過配置的名稱,獲取對應的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); }
這個是處理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; }
這個設計方式跟上面相似,也是經過配置信息的名稱,獲取對應的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; }