Spring Cloud Gateway 源码解析(2) —— 路由

基本组件

路由定位器(RouteDefinitionLocator )

RouteDefinitionLocator 负责读取路由配置(RouteDefinition ),Gateway实现了多种Locator。

public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}

  •  PropertiesRouteDefinitionLocator

从配置文件( 例如,YML / Properties 等 ) 读取

  • RouteDefinitionRepository

从存储器( 例如,内存 / Redis / MySQL 等 )读取。

  • DiscoveryClientRouteDefinitionLocator

从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取。

  • CompositeRouteDefinitionLocator

组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

  • CachingRouteDefinitionLocator

已经被 CachingRouteLocator 取代。
      

路由定义(RouteDefinition)

@Validated
public class RouteDefinition {

	@NotEmpty
	private String id = UUID.randomUUID().toString();

	@NotEmpty
	@Valid
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
	private URI uri;

	private int order = 0;
}
  • id 属性,ID 编号,唯一
  • predicates 属性,谓语定义数组。请求通过 predicates 判断是否匹配。在 Route 里,PredicateDefinition 转换成 Predicate 。
  • filters 属性,过滤器定义数组。在 Route 里,FilterDefinition 转换成 GatewayFilter 。
  • uri 属性,路由向的 URI 。
  • order 属性,顺序。当请求匹配到多个路由时,使用顺序的。

RouteDefinition 提供 text 字符串创建对象(yaml配置中属性值),格式为:

${id}=${uri},${predicates[0]},${predicates[1]}...${predicates[n]}

public RouteDefinition(String text) ;

 PredicateDefinition

@Validated
public class PredicateDefinition {

    /**
     * 谓语定义名字,通过 name 对应到 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 的实现类
     */
    @NotNull
	private String name;
    /**
     * 参数数组
     */
	private Map<String, String> args = new LinkedHashMap<>();
}

提供了构造函数:

/**
 * 根据 text 创建 PredicateDefinition
 *
 * @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
 *             例如 Host=iocoder.cn
 */
public PredicateDefinition(String text);

FilterDefinition

@Validated
public class FilterDefinition {

    /**
     * 过滤器定义名字。通过 name 对应到 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 的实现类
     */
	@NotNull
	private String name;
    /**
     * 参数数组
     */
	private Map<String, String> args = new LinkedHashMap<>();
}

提供了构造函数:

/**
 * 根据 text 创建 FilterDefinition
 *
 * @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
 *             例如 AddRequestParameter=foo, bar
 */
public FilterDefinition(String text);

CompositeRouteDefinitionLocator

组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions)
				.flatMap(routeDefinition -> {
					if (routeDefinition.getId() == null) {
						return randomId().map(id -> {
							routeDefinition.setId(id);
							if (log.isDebugEnabled()) {
								log.debug(
										"Id set on route definition: " + routeDefinition);
							}
							return routeDefinition;
						});
					}
					return Mono.just(routeDefinition);
				});
	}

路由定位器 (RouteLocator)

  • RouteLocator 可以直接自定义路由( org.springframework.cloud.gateway.route.Route ) ,也可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route 。
  • RoutePredicateHandlerMapping 使用 RouteLocator 获得 Route 信息。

Route

Route与RouteDefinition结构相似。同时实现了Order接口。

public class Route implements Ordered {

    /**
     * 路由编号
     */
    private final String id;
    /**
     * 路由向的 URI
     */
    private final URI uri;
    /**
     * 顺序
     */
    private final int order;
    /**
     * 谓语数组
     */
    private final Predicate<ServerWebExchange> predicate;
    /**
     * 过滤器数组
     */
    private final List<GatewayFilter> gatewayFilters;
}

Route 内置 Builder 类,根据RouteDefinition 构造对象。predicate / gatewayFilters 属性,需要调用 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
	}

 

RouteDefinitionLocator解析

PropertiesRouteDefinitionLocator 

GatewayProperties 中获取路由信息。

public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

	private final GatewayProperties properties;

	public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
		this.properties = properties;
	}

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return Flux.fromIterable(this.properties.getRoutes());
	}

}

GatewayProperties

GatewayProperties ,从配置文件读取 :

  • 路由配置

通过 spring.cloud.gateway.routes 配置

  • 默认过滤器配置。当 RouteDefinition => Route 时,会将过滤器配置添加到每个 Route 。

通过 spring.cloud.gateway.default-filters 配置

@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
	/**
	 * List of Routes.
	 */
	@NotNull
	@Valid
	private List<RouteDefinition> routes = new ArrayList<>();

	/**
	 * List of filter definitions that are applied to every route.
	 */
	private List<FilterDefinition> defaultFilters = new ArrayList<>();
}

RouteDefinitionRepository 

public interface RouteDefinitionRepository
		extends RouteDefinitionLocator, RouteDefinitionWriter {

}

类继承关系如下: 

RouteDefinitionWriter 

RouteDefinitionWriter ,路由配置写入接口。该接口定义了保存删除两个方法

public interface RouteDefinitionWriter {

    /**
     * 保存路由配置
     *
     * @param route 路由配置
     * @return Mono<Void>
     */
    Mono<Void> save(Mono<RouteDefinition> route);

    /**
     * 删除路由配置
     *
     * @param routeId 路由编号
     * @return Mono<Void>
     */
    Mono<Void> delete(Mono<String> routeId);
}

InMemoryRouteDefinitionRepository

基于内存为存储器的 RouteDefinitionLocator

public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {

	private final Map<String, RouteDefinition> routes = synchronizedMap(
			new LinkedHashMap<String, RouteDefinition>());

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return Flux.fromIterable(routes.values());
	}
}

路由信息构造:

@Override
	public Mono<Void> save(Mono<RouteDefinition> route) {
		return route.flatMap(r -> {
			if (StringUtils.isEmpty(r.getId())) {
				return Mono.error(new IllegalArgumentException("id may not be empty"));
			}
			routes.put(r.getId(), r);
			return Mono.empty();
		});
	}

	@Override
	public Mono<Void> delete(Mono<String> routeId) {
		return routeId.flatMap(id -> {
			if (routes.containsKey(id)) {
				routes.remove(id);
				return Mono.empty();
			}
			return Mono.defer(() -> Mono.error(
					new NotFoundException("RouteDefinition not found: " + routeId)));
		});
	}

自定义RouteDefinitionRepository

可以自定义RouteDefinitionRepository,如果没有自定义,才使用内存存储。

// GatewayAutoConfiguration.java
@Bean 
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
    return new InMemoryRouteDefinitionRepository();
}

DiscoveryClientRouteDefinitionLocator 

DiscoveryClientRouteDefinitionLocator 通过调用 org.springframework.cloud.client.discovery.DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组。

public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
	private final DiscoveryLocatorProperties properties;

	private final String routeIdPrefix;

	private final SimpleEvaluationContext evalCtxt;

	private Flux<List<ServiceInstance>> serviceInstances;

}

@Override
	public Flux<RouteDefinition> getRouteDefinitions() {

		SpelExpressionParser parser = new SpelExpressionParser();
		Expression includeExpr = parser
				.parseExpression(properties.getIncludeExpression());
		Expression urlExpr = parser.parseExpression(properties.getUrlExpression());

        //构造服务实例是否可用predicate。
		Predicate<ServiceInstance> includePredicate;
		if (properties.getIncludeExpression() == null
				|| "true".equalsIgnoreCase(properties.getIncludeExpression())) {
			includePredicate = instance -> true;
		}
		else {
			includePredicate = instance -> {
				Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);
				if (include == null) {
					return false;
				}
				return include;
			};
		}

		return serviceInstances.filter(instances -> !instances.isEmpty())
                //返回可用实例
				.map(instances -> instances.get(0)).filter(includePredicate)
				.map(instance -> {
//构建definition
					RouteDefinition routeDefinition = buildRouteDefinition(urlExpr,
							instance);

					final ServiceInstance instanceForEval = new DelegatingServiceInstance(
							instance, properties);
//拷贝PredicateDefinition 
					for (PredicateDefinition original : this.properties.getPredicates()) {
						PredicateDefinition predicate = new PredicateDefinition();
						predicate.setName(original.getName());
						for (Map.Entry<String, String> entry : original.getArgs()
								.entrySet()) {
//计算表达式值。
							String value = getValueFromExpr(evalCtxt, parser,
									instanceForEval, entry);
							predicate.addArg(entry.getKey(), value);
						}
						routeDefinition.getPredicates().add(predicate);
					}
//拷贝FilterDefinition 
					for (FilterDefinition original : this.properties.getFilters()) {
						FilterDefinition filter = new FilterDefinition();
						filter.setName(original.getName());
						for (Map.Entry<String, String> entry : original.getArgs()
								.entrySet()) {
//计算表达式值。
							String value = getValueFromExpr(evalCtxt, parser,
									instanceForEval, entry);
							filter.addArg(entry.getKey(), value);
						}
						routeDefinition.getFilters().add(filter);
					}

					return routeDefinition;
				});
	}

RouteLocator解析

RouteLocator

路由定位器接口,定义获得路由数组的方法

public interface RouteLocator {
	Flux<Route> getRoutes();
}

CompositeRouteLocator

组合多种 RouteLocator 的实现类,为 RoutePredicateHandlerMapping 提供统一入口访问路由

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

}

CachingRouteLocator

CachingRouteLocator ,缓存路由的 RouteLocator 实现类。RoutePredicateHandlerMapping 调用 CachingRouteLocator 的 RouteLocator#getRoutes() 方法,获取路由。

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;
		routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
				.onCacheMissResume(this::fetch);
	}
}

RouteDefinitionRouteLocator 

RouteDefinitionRouteLocator ,基于 RouteDefinitionLocator 的 RouteLocator 实现类。RouteDefinitionRouteLocator 从 RouteDefinitionLocator 获取 RouteDefinition ,转换成 Route 

public class RouteDefinitionRouteLocator
		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {

	/**
	 * Default filters name.
	 */
	public static final String DEFAULT_FILTERS = "defaultFilters";

	protected final Log logger = LogFactory.getLog(getClass());

	private final RouteDefinitionLocator routeDefinitionLocator;

	private final ConfigurationService configurationService;

	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();

	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

	private final GatewayProperties gatewayProperties;
}

构造函数


	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
			List<RoutePredicateFactory> predicates,
			List<GatewayFilterFactory> gatewayFilterFactories,
			GatewayProperties gatewayProperties,
			ConfigurationService configurationService) {
		this.routeDefinitionLocator = routeDefinitionLocator;
		this.configurationService = configurationService;
		initFactories(predicates);
		gatewayFilterFactories.forEach(
				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
		this.gatewayProperties = gatewayProperties;
	}

获得 Route


	@Override
	public Flux<Route> getRoutes() {
       //routeDefinitionLocator获取RouteDefinitions,转换成Route
		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());
				}
			});
		}

		return routes.map(route -> {
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition matched: " + route.getId());
			}
			return route;
		});
	}

//合并predicate,合并filters,构造一个route。
	private Route convertToRoute(RouteDefinition routeDefinition) {
		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);

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

自定义 RouteLocator

RouteLocatorBuilder用于自定义RouteLocator

public class RouteLocatorBuilder {	
    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;
		}
}
  • RouteSpec:route builder。
  • UriSpec:可以添加一个Uri
  • PredicateSpec:可以应用到一个Uri的Predicate。
  • BooleanOpSpec:逻辑操作Predicate。
  • GatewayFilterSpec:GatewayFilter

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章