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

 

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