• 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;
    			}
    		}
    	};
    }
    
  • 相关阅读:
    你不能错过的【Python爬虫】测试3(爬取所有内容 + 完整源代码 + 架构 + 结果)
    【YOLOv7/YOLOv5系列算法改进NO.47】改进激活函数为GELU
    一文带你了解动态NAT以及NAPT实验配置
    遗传算法在TSP中的两步求解(Matlab代码实现)
    Dubbo入门案例
    【MMDetection3D】MVXNet踩坑笔记
    SpringBoot 实现启动项目后立即执行方法的几种方式
    双vip的MySQL高可用集群
    EMIF 接口
    双位置继电器DLS-42/6-4/DC110V
  • 原文地址:https://blog.csdn.net/qq_36851469/article/details/126949853