3、SpringCloud之gateway动态路由

问题一、针对Gateway Filter文件配置与显示自定义的生效问题

  1. 配置文件对应的RouteLocator为RouteDefinitionRouteLocator。
  2. 显示的自定义RouteLocator。

以上两种方式都不支持动态路由的方式

事件订阅机制

public class GatewayAutoConfiguration {
	@Bean
	public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
			List<GatewayFilterFactory> gatewayFilters,
			List<RoutePredicateFactory> predicates,
			//PropertiesRouteDefinitionLocator、InMemoryRouteDefinitionRepository
			RouteDefinitionLocator routeDefinitionLocator,
			ConfigurationService configurationService) {
		return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
				gatewayFilters, properties, configurationService);
	}

	@Bean
	@Primary
	@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
	public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
	//routeLocators 中包含了上述两种类型的RouteLocator
		return new CachingRouteLocator(
				new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
	}
	//发布订阅者模式
	@Bean
	public RouteRefreshListener routeRefreshListener(
			ApplicationEventPublisher publisher) {
		return new RouteRefreshListener(publisher);
	}
}
  1. 监听器【订阅者】RouteRefreshListener其实例在初始化完成后会被系统调用其RouteRefreshListener#onApplicationEvent方法。
  2. RouteRefreshListener存在RefreshRoutesEvent事件。该事件最终会被ApplicationEventPublisher发布者发布。
  3. RefreshRoutesEvent事件最终会被CachingRouteLocator监听订阅。其目的就是处理CachingRouteLocator持有的多个RouteLocator。

CompositeRouteLocator

public class CompositeRouteLocator implements RouteLocator {
	private final Flux<RouteLocator> delegates;
	public CompositeRouteLocator(Flux<RouteLocator> delegates) {
		this.delegates = delegates;
	}
	@Override
	public Flux<Route> getRoutes() {
		return this.delegates.flatMap(RouteLocator::getRoutes);
	}
}
  • 维护服务启动后初始化完成的RouteLocator。
  • 充当CachingRouteLocator的代理RouteLocator。

CachingRouteLocator

public class CachingRouteLocator
		implements Ordered, RouteLocator, ApplicationListener<RefreshRoutesEvent> {

	private static final String CACHE_KEY = "routes";
	private final RouteLocator delegate;
	private final Flux<Route> routes;
	private final Map<String, List> cache = new ConcurrentHashMap<>();
	public CachingRouteLocator(RouteLocator delegate) {
		this.delegate = delegate;
		// 1、订阅后先从缓存cache获取Route。
		// 2、如果缓存中没有通过fetch获取,并将其设置到缓存cache中
		routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
				.onCacheMissResume(this::fetch);
	}

	private Flux<Route> fetch() {
		// 根据order配置对全部Route进行排序,值越小优先级越高
		return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
	}
	// 该方法会在请求过程中通过以下方法获取服务中初始化的全部Route
	@Override
	public Flux<Route> getRoutes() {
		return this.routes;
	}
	@Override
	public void onApplicationEvent(RefreshRoutesEvent event) {
		fetch().materialize().collect(Collectors.toList())
				.doOnNext(routes -> cache.put(CACHE_KEY, routes)).subscribe();
	}
	
	public Flux<Route> refresh() {
		this.cache.clear();
		return this.routes;
	}
}
  • CachingRouteLocator充当监听器订阅者。
  • 通过代理类CompositeRouteLocator获取全部的RouteLocator。

作用:

  1. fetch目的是获取全部Route。
  2. 订阅后CacheFlux.lookup 会将全部Route放到缓存cache中。
  3. 如果不执行refresh方法,虽然通过事件机制可以定时更新缓存cache中Route集合,但是并不会改变集合routes。
  4. 所以如果要实现动态路由或者动态加载配置信息需要触发refresh方法,通过事件机制重新加载缓存cache,也就是触发RouteDefinitionRouteLocator重新加载配置信息。
  5. 处理请求中如果routes没有值就会从缓存中加载最新的。

显示自定义的RouteLocator

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
	// r:PredicateSpec
    return builder.routes().route(r -> r
            .path("/custom/filter/**")
            .uri("lb://provider-service")
            .filter(new CustomGwFilter())
            .id("provider-service")).build();
}

RouteLocatorBuilder目的是创建Route。

public class RouteLocatorBuilder {

	private ConfigurableApplicationContext context;
	public RouteLocatorBuilder(ConfigurableApplicationContext context) {
		this.context = context;
	}
	public Builder routes() {
		return new Builder(context);
	}
	public static class Builder {
		private List<Route.AsyncBuilder> routes = new ArrayList<>();
		
		private ConfigurableApplicationContext context;
		public Builder(ConfigurableApplicationContext context) {
			this.context = context;
		}
		public Builder route(String id, Function<PredicateSpec, Route.AsyncBuilder> fn) {
			// new RouteSpec(this).id(id):返回 PredicateSpec,可以作用于 路径 相关的断言
			// 回调自定义的uri、path、filter
			Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).id(id));
			add(routeBuilder);
			return this;
		}
		public Builder route(Function<PredicateSpec, Route.AsyncBuilder> fn) {
			Route.AsyncBuilder routeBuilder = fn.apply(new RouteSpec(this).randomId());
			add(routeBuilder);
			return this;
		}
		// 遍历集合 routes,通过响应式编程创建真正的Route
		public RouteLocator build() {
			return () -> Flux.fromIterable(this.routes)
					.map(routeBuilder -> routeBuilder.build());
		}
		void add(Route.AsyncBuilder route) {
			routes.add(route);
		}
	}

	public static class RouteSpec {
		private final Route.AsyncBuilder routeBuilder = Route.async();
		private final Builder builder;
		RouteSpec(Builder builder) {
			this.builder = builder;
		}
		public PredicateSpec id(String id) {
			this.routeBuilder.id(id);
			return predicateBuilder();
		}
		public PredicateSpec randomId() {
			return id(UUID.randomUUID().toString());
		}
		private PredicateSpec predicateBuilder() {
			return new PredicateSpec(this.routeBuilder, this.builder);
		}
	}
}
  • RouteLocatorBuilder存在两个内部静态类:RouteSpec、Builder。
  • RouteSpec:创建PredicateSpec。
  • RouteLocatorBuilder作用是通过PredicateSpec创建Route.AsyncBuilder。
  • 通过RouteLocatorBuilder#route方法获取到的 Route.AsyncBuilder 封装了自定义的predict断言、uri、filter等。
  • 将返回的全部Route.AsyncBuilder由RouteLocatorBuilder内部静态类Builder的集合属性routes持有。

PredicateSpec

public class PredicateSpec extends UriSpec {

	PredicateSpec(Route.AsyncBuilder routeBuilder, RouteLocatorBuilder.Builder builder) {
		super(routeBuilder, builder);//由父类UriSpec持有routeBuilder、builder
	}

	public BooleanSpec path(String... patterns) {
		//内部方法返回DefaultAsyncPredicate
		return asyncPredicate(getBean(PathRoutePredicateFactory.class)
				// 调用父类RoutePredicateFactory#applyAsync
				.applyAsync(c -> c.setPatterns(Arrays.asList(patterns))));
	}
	//predicate:DefaultAsyncPredicate
	public BooleanSpec asyncPredicate(AsyncPredicate<ServerWebExchange> predicate) {
		this.routeBuilder.asyncPredicate(predicate);
		return new BooleanSpec(this.routeBuilder, this.builder);
	}
}
public class UriSpec {

	final Route.AsyncBuilder routeBuilder;

	final RouteLocatorBuilder.Builder builder;

	UriSpec(Route.AsyncBuilder routeBuilder, RouteLocatorBuilder.Builder builder) {
		this.routeBuilder = routeBuilder;
		this.builder = builder;
	}
	public Route.AsyncBuilder uri(String uri) {
		return this.routeBuilder.uri(uri);
	}

	public Route.AsyncBuilder uri(URI uri) {
		return this.routeBuilder.uri(uri);
	}
}
  • PredicateSpec获取真正断言DefaultAsyncPredicate。
  • 将获取到的DefaultAsyncPredicate交给 Route.AsyncBuilder。
  • 返回处理uri的BooleanSpec。

Route

public class Route implements Ordered {

	private final String id;
	private final URI uri;
	private final int order;
	private final AsyncPredicate<ServerWebExchange> predicate;
	private final List<GatewayFilter> gatewayFilters;
	private final Map<String, Object> metadata;
	@Deprecated
	private Route(String id, URI uri, int order,
			AsyncPredicate<ServerWebExchange> predicate,
			List<GatewayFilter> gatewayFilters) {
		this(id, uri, order, predicate, gatewayFilters, new HashMap<>());
	}

	private Route(String id, URI uri, int order,
			AsyncPredicate<ServerWebExchange> predicate,
			List<GatewayFilter> gatewayFilters, Map<String, Object> metadata) {
		this.id = id;
		this.uri = uri;
		this.order = order;
		this.predicate = predicate;
		this.gatewayFilters = gatewayFilters;
		this.metadata = metadata;
	}
	public static Builder builder() {
		return new Builder();
	}
	public static Builder builder(RouteDefinition routeDefinition) {
		// @formatter:off
		return new Builder().id(routeDefinition.getId())
				.uri(routeDefinition.getUri())
				.order(routeDefinition.getOrder())
				.metadata(routeDefinition.getMetadata());
		// @formatter:on
	}

	public static AsyncBuilder async() {
		return new AsyncBuilder();
	}

	public static AsyncBuilder async(RouteDefinition routeDefinition) {
		// @formatter:off
		return new AsyncBuilder().id(routeDefinition.getId())
				.uri(routeDefinition.getUri())
				.order(routeDefinition.getOrder())
				.metadata(routeDefinition.getMetadata());
		// @formatter:on
	}
	public abstract static class AbstractBuilder<B extends AbstractBuilder<B>> {

		protected String id;

		protected URI uri;

		protected int order = 0;

		protected List<GatewayFilter> gatewayFilters = new ArrayList<>();

		protected Map<String, Object> metadata = new HashMap<>();

		protected AbstractBuilder() {
		}

		protected abstract B getThis();

		public B uri(URI uri) {
			this.uri = uri;
			String scheme = this.uri.getScheme();
			if (this.uri.getPort() < 0 && scheme.startsWith("http")) {
				// default known http ports
				int port = this.uri.getScheme().equals("https") ? 443 : 80;
				this.uri = UriComponentsBuilder.fromUri(this.uri).port(port).build(false)
						.toUri();
			}
			return getThis();
		}

		public B filter(GatewayFilter gatewayFilter) {
			this.gatewayFilters.add(gatewayFilter);
			return getThis();
		}
		
		// 由 RouteLocatorBuilder#build方法调用返回Route
		public Route build() {
			AsyncPredicate<ServerWebExchange> predicate = getPredicate();
			return new Route(this.id, this.uri, this.order, predicate,
					this.gatewayFilters, this.metadata);
		}
	}

	public static class AsyncBuilder extends AbstractBuilder<AsyncBuilder> {

		protected AsyncPredicate<ServerWebExchange> predicate;

		@Override
		public AsyncPredicate<ServerWebExchange> getPredicate() {
			return this.predicate;
		}

		public AsyncBuilder predicate(Predicate<ServerWebExchange> predicate) {
			return asyncPredicate(toAsyncPredicate(predicate));
		}

		public AsyncBuilder asyncPredicate(AsyncPredicate<ServerWebExchange> predicate) {
			this.predicate = predicate;
			return this;
		}

			this.predicate = this.predicate.and(predicate);
			return this;
		}

		public AsyncBuilder or(AsyncPredicate<ServerWebExchange> predicate) {
			this.predicate = this.predicate.or(predicate);
			return this;
		}

		public AsyncBuilder negate() {
			this.predicate = this.predicate.negate();
			return this;
		}

	}

	public static class Builder extends AbstractBuilder<Builder> {

		protected Predicate<ServerWebExchange> predicate;

		@Override
		protected Builder getThis() {
			return this;
		}

		@Override
		public AsyncPredicate<ServerWebExchange> getPredicate() {
			return ServerWebExchangeUtils.toAsyncPredicate(this.predicate);
		}

		public Builder and(Predicate<ServerWebExchange> predicate) {
			this.predicate = this.predicate.and(predicate);
			return this;
		}

		public Builder or(Predicate<ServerWebExchange> predicate) {
			this.predicate = this.predicate.or(predicate);
			return this;
		}

		public Builder negate() {
			this.predicate = this.predicate.negate();
			return this;
		}
	}
}
  • Route类中存在静态内部类Builder、AsyncBuilder、AbstractBuilder。
  • AsyncBuilder 的抽象父类 AbstractBuilder 中持有Route相关的URI、gatewayFilters。
  • AsyncBuilder持有predicate。
  • uri、gatewayFilters只能由父类AbstractBuilder处理。

RoutePredicateFactory

public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {
	default AsyncPredicate<ServerWebExchange> applyAsync(Consumer<C> consumer) {
		C config = newConfig();// PathRoutePredicateFactory内部静态类 Config
		consumer.accept(config);// PathRoutePredicateFactory【Config】持有 路由匹配的模式 patterns 设置
		beforeApply(config);
		return applyAsync(config);
	}
	
	default AsyncPredicate<ServerWebExchange> applyAsync(C config) {
		//PathRoutePredicateFactory#apply,返回 GatewayPredicate
		return toAsyncPredicate(apply(config));//DefaultAsyncPredicate
	}
}

PathRoutePredicateFactory

public Predicate<ServerWebExchange> apply(Config config) {
	final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
	synchronized (this.pathPatternParser) {
		pathPatternParser.setMatchOptionalTrailingSeparator(
				config.isMatchOptionalTrailingSeparator());
		config.getPatterns().forEach(pattern -> {
			PathPattern pathPattern = this.pathPatternParser.parse(pattern);
			pathPatterns.add(pathPattern);
		});
	}
	return new GatewayPredicate() {
		@Override
		public boolean test(ServerWebExchange exchange) {
			PathContainer path = parsePath(
					exchange.getRequest().getURI().getRawPath());

			Optional<PathPattern> optionalPathPattern = pathPatterns.stream()
					.filter(pattern -> pattern.matches(path)).findFirst();

			if (optionalPathPattern.isPresent()) {
				PathPattern pathPattern = optionalPathPattern.get();
				traceMatch("Pattern", pathPattern.getPatternString(), path, true);
				PathMatchInfo pathMatchInfo = pathPattern.matchAndExtract(path);
				putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());
				return true;
			}
			else {
				traceMatch("Pattern", config.getPatterns(), path, false);
				return false;
			}
		}
	};
}

你可能感兴趣的:(SpringCloud,spring,cloud,gateway,java)