欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringCloudGateway小记

程序员文章站 2022-06-14 19:55:38
...

GateWayProperties

public class GatewayProperties {
	/**
	 * List of Routes.
	 */
	private List<RouteDefinition> routes = new ArrayList<>();

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

	private List<MediaType> streamingMediaTypes = Arrays
			.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);

对应配置文件中:

spring:
  cloud:
    gateway:
      default-filters:
      - PrefixPath=/httpbin
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
      routes:
        - id: websocket_test
        uri: ws://localhost:9000
        order: 9000
        predicates:
        - Path=/echo
      # =====================================
      - id: default_path_to_httpbin
        uri: ${test.uri}
        order: 10000
        predicates:
        - Path=/**

List<FilterDefinition> defaultFilters

org.springframework.cloud.gateway.filter.FilterDefinition

public class FilterDefinition {
	private String name;
	private Map<String, String> args = new LinkedHashMap<>();
	public FilterDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			setName(text);
			return;
		}
		setName(text.substring(0, eqIdx));

		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

		for (int i = 0; i < args.length; i++) {
			this.args.put(NameUtils.generateName(i), args[i]);
		}
	}
	
-------------
public final class NameUtils {
	/**
	 * Generated name prefix.
	 */
	public static final String GENERATED_NAME_PREFIX = "_genkey_";

	public static String generateName(int i) {
		return GENERATED_NAME_PREFIX + i;
	}

配置DEMO

spring: 
  cloud:
    gateway:
      default-filters:
      - PrefixPath=/httpbin
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar

构造函数 参数只有一个字符串
name=value1,value2,value3,…
故每个FilterDefinition 的name与args 的Value 为外部配置,args 的Key 为自动生成 规则为 _genkey_+序号

List routes

org.springframework.cloud.gateway.route.RouteDefinition

public class RouteDefinition {
	private String id;
	private List<PredicateDefinition> predicates = new ArrayList<>();
	private List<FilterDefinition> filters = new ArrayList<>();
	private URI uri;
	private Map<String, Object> metadata = new HashMap<>();
	private int order = 0;
	public RouteDefinition() {
	}
	public RouteDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			throw new ValidationException("Unable to parse RouteDefinition text '" + text
					+ "'" + ", must be of the form name=value");
		}
		setId(text.substring(0, eqIdx));
		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
		setUri(URI.create(args[0]));
		for (int i = 1; i < args.length; i++) {
			this.predicates.add(new PredicateDefinition(args[i]));
		}
	}

配置DEMO

spring:
  cloud:
    gateway:
      routes:
      - id: websocket_test
        uri: ws://localhost:9000
        order: 9000
        predicates:
        - Path=/echo
      # =====================================
      - id: default_path_to_httpbin
        uri: ${test.uri}
        order: 10000
        predicates:
        - Path=/**

List predicates

配置匹配表达式

public class PredicateDefinition {
	private String name;
	private Map<String, String> args = new LinkedHashMap<>();
	public PredicateDefinition() {
	}
	public PredicateDefinition(String text) {
		int eqIdx = text.indexOf('=');
		if (eqIdx <= 0) {
			throw new ValidationException("Unable to parse PredicateDefinition text '"
					+ text + "'" + ", must be of the form name=value");
		}
		setName(text.substring(0, eqIdx));
		String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
		for (int i = 0; i < args.length; i++) {
			this.args.put(NameUtils.generateName(i), args[i]);
		}
	}

构造函数 参数只有一个字符串
name=value1,value2,value3,…
故每个PredicateDefinition 的name与args 的Value 为外部配置,args 的Key 为自动生成 规则为 _genkey_+序号

Route

org.springframework.cloud.gateway.route.Route
路由的基础单位
业务代码:

org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute
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;

路由工厂

org.springframework.cloud.gateway.route.RouteLocator

/**
 * @author Spencer Gibb
 */
// TODO: rename to Routes?
public interface RouteLocator {

	Flux<Route> getRoutes();

}

默认的 SpringCloudGateWay 的 路由工厂使用

org.springframework.cloud.gateway.route.CachingRouteLocator

SpringCloudGateway小记

CachingRouteLocator 实现

org.springframework.cloud.gateway.config.GatewayAutoConfiguration#cachedCompositeRouteLocator

SpringCloudGateway小记


	public CachingRouteLocator(RouteLocator delegate) {
		this.delegate = delegate;
		routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
				.onCacheMissResume(this::fetch);
	}

才用组合委托设计实现

基础 RouteLocator 定义

Bean 定义模式

 @Bean
    open fun additionalRouteLocator(builder: RouteLocatorBuilder) = builder.routes {
        route(id = "test-kotlin") {
            host("kotlin.abc.org") and path("/image/png")
            filters {
                prefixPath("/httpbin")
                addResponseHeader("X-TestHeader", "foobar")
            }
            uri(uri)
        }
    }
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
            .filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR"))
                .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
        .build();
}

使用YAML 配置文件

spring:
  cloud:
    gateway:
      default-filters:
      - PrefixPath=/
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar

      routes:
      - id: websocket_test
        uri: ws://localhost:9000
        order: 9000
        predicates:
        - Path=/echo

配置文件读取上GateWayProperties

配置文件实例化 RouteLocator

RouteDefinition 定义 RouteLocator

	public List<RouteDefinition> getRoutes() {
		return routes;
	}

org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator

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

}

在此加载 RouteLocator 的定义文件 (RouteDefinition)

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getRoutes


	@Override
	public Flux<Route> getRoutes() {
		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
				.map(this::convertToRoute);
	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 转换为 Router

Gateway 总路由

GateWay 映射

org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping

@Override
	protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
		// don't handle requests on management port if set and different than server port
		if (this.managementPortType == DIFFERENT && this.managementPort != null
				&& exchange.getRequest().getURI().getPort() == this.managementPort) {
			return Mono.empty();
		}
		exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

		return lookupRoute(exchange)
				// .log("route-predicate-handler-mapping", Level.FINER) //name this
				.flatMap((Function<Route, Mono<?>>) r -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					if (logger.isDebugEnabled()) {
						logger.debug(
								"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
					}

					exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
					return Mono.just(webHandler);
				}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					if (logger.isTraceEnabled()) {
						logger.trace("No RouteDefinition found for ["
								+ getExchangeDesc(exchange) + "]");
					}
				})));
	}

路由转发与过滤器

org.springframework.web.reactive.DispatcherHandler#handle
使用SpringWebFlux

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}