天天看点

Spring Cloud Gateway 源码解析(1) —— 基础Gateway初始化核心组件构建

目录

Gateway初始化

启用Gateway

GatewayClassPathWarningAutoConfiguration

GatewayLoadBalancerClientAutoConfiguration

GatewayAutoConfiguration

网关的开启和关闭

GlobalFilters

RoutePredicateFactory

 NettyConfiguration

核心组件构建

组件

Route

AsyncPredicate

GatewayFilter

Route构建

外部化配置

编程方式

构建原理

GatewayProperties

RouteDefinition

 FilterDefinition

PredicateDefinition

RoutePredicateFactory

GatewayFilterFactory

RouteLocator

RouteDefinitionRouteLocator

本文章源码为2.2.2-release,github:https://github.com/spring-cloud/spring-cloud-gateway/tree/v2.2.2.RELEASE

Gateway初始化

启用Gateway

官方示例中,启用Gateway,使用了@EnableAutoConfiguration注解。

@EnableAutoConfiguration
@Import(AdditionalRoutes.class)
public class GatewaySampleApplication {
......
}
           

@EnableAutoConfiguration注解会引入:

Spring Cloud Gateway 源码解析(1) —— 基础Gateway初始化核心组件构建

这些自动配置类都放在org.springframework.cloud.gateway.config下。在加载GatewayAutoConfiguration之前,会加载一些配置,通过@AutoConfigureAfter,@AutoConfigureBefore注解来控制加载顺序。

GatewayClassPathWarningAutoConfiguration

用于检查项目是否正确导入 

spring-boot-starter-webflux

 依赖,而不是错误导入 

spring-boot-starter-web

 依赖。

@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
	protected static class SpringMvcFoundOnClasspathConfiguration {
		public SpringMvcFoundOnClasspathConfiguration() {
			log.warn(BORDER
					+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
					+ "Please remove spring-boot-starter-web dependency." + BORDER);
		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
	protected static class WebfluxMissingFromClasspathConfiguration {
		public WebfluxMissingFromClasspathConfiguration() {
			log.warn(BORDER + "Spring Webflux is missing from the classpath, "
					+ "which is required for Spring Cloud Gateway at this time. "
					+ "Please add spring-boot-starter-webflux dependency." + BORDER);
		}

	}

}
           

GatewayLoadBalancerClientAutoConfiguration

初始化 LoadBalancerClientFilter,可以使用LoadBalancerProperties加载配置信息。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ LoadBalancerClient.class, RibbonAutoConfiguration.class,
		DispatcherHandler.class })
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class GatewayLoadBalancerClientAutoConfiguration {

	@Bean
	@ConditionalOnBean(LoadBalancerClient.class)
	@ConditionalOnMissingBean({ LoadBalancerClientFilter.class,
			ReactiveLoadBalancerClientFilter.class })
	public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
			LoadBalancerProperties properties) {
		return new LoadBalancerClientFilter(client, properties);
	}

}
           

配置:spring.cloud.gateway.loadbalancer

@ConfigurationProperties("spring.cloud.gateway.loadbalancer")
public class LoadBalancerProperties {
	private boolean use404;
	public boolean isUse404() {
		return use404;
	}
	public void setUse404(boolean use404) {
		this.use404 = use404;
	}
}
           

GatewayAutoConfiguration

GatewayAutoConfiguration是Gateway的核心配置类。仅当时reactive类型 服务时才加载。

会初始化一些组件:

  • GlobalFilters
  • RoutePredicateFactory
  • RouteDefinitionLocator
  • NettyConfiguration
  • FilteringWebHandler
  • GatewayProperties
  • PrefixPathGatewayFilterFactory
  • RouteDefinitionLocator
  • RouteLocator
  • RoutePredicateHandlerMapping
  • GatewayWebfluxEndpoint

网关的开启和关闭

从 GatewayAutoConfiguration 上的注解 

@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)

 ,我们可以看出 :

  • 通过 

    spring.cloud.gateway.enabled

     配置网关的开启与关闭。
  • matchIfMissing = true  

     =>   网关默认开启。

GlobalFilters

Spring Cloud Gateway 源码解析(1) —— 基础Gateway初始化核心组件构建

RoutePredicateFactory

Spring Cloud Gateway 源码解析(1) —— 基础Gateway初始化核心组件构建

 NettyConfiguration

Spring Cloud Gateway 源码解析(1) —— 基础Gateway初始化核心组件构建

核心组件构建

组件

Route

Route 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。

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;
	public int getOrder() {
		return order;
	}
}
           

Route 主要定义了如下几个部分:

① id,标识符,区别于其他 Route。

② destination uri,路由指向的目的地 uri,即客户端请求最终被转发的目的地。

③ order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。

④ predicate,谓语,表示匹配该 Route 的前置条件,即满足相应的条件才会被路由到目的地 uri。

⑤ gateway filters,过滤器用于处理切面逻辑,如路由转发前修改请求头等。

AsyncPredicate

Predicate 即 Route 中所定义的部分,用于条件匹配,请参考 Java 8 提供的 Predicate 和 Function。

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {

	default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
		return new AndAsyncPredicate<>(this, other);
	}

	default AsyncPredicate<T> negate() {
		return new NegateAsyncPredicate<>(this);
	}

	default AsyncPredicate<T> or(AsyncPredicate<? super T> other) {
		return new OrAsyncPredicate<>(this, other);
	}

	static AsyncPredicate<ServerWebExchange> from(
			Predicate<? super ServerWebExchange> predicate) {
		return new DefaultAsyncPredicate<>(GatewayPredicate.wrapIfNeeded(predicate));
	}
}
           

AsyncPredicate 定义了 3 种逻辑操作方法:

① and ,与操作,即两个 Predicate 组成一个,需要同时满足。

② negate,取反操作,即对 Predicate 匹配结果取反。

③ or,或操作,即两个 Predicate 组成一个,只需满足其一。

GatewayFilter

很多框架都有 Filter 的设计,用于实现可扩展的切面逻辑。

public interface GatewayFilter extends ShortcutConfigurable {

	/**
	 * Name key.
	 */
	String NAME_KEY = "name";

	/**
	 * Value key.
	 */
	String VALUE_KEY = "value";

	/**
	 * Process the Web request and (optionally) delegate to the next {@code WebFilter}
	 * through the given {@link GatewayFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

}
           

Filter 最终是通过 filter chain 来形成链式调用的,每个 filter 处理完 pre filter 逻辑后委派给 filter chain,filter chain 再委派给下一下 filter。

public interface GatewayFilterChain {
	Mono<Void> filter(ServerWebExchange exchange);
}
           

Route构建

外部化配置

参考:Spring Cloud Gateway介绍(一),Spring Cloud Gateway介绍(二)

编程方式

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { // ①
    return builder.routes() // ②
            .route(r -> r.host("**.abc.org").and().path("/image/png") // ③
                .filters(f ->
                        f.addResponseHeader("X-TestHeader", "foobar")) // ④
                .uri("http://httpbin.org:80") // ⑤
            )
            .build();
}
           

① RouteLocatorBuilder 在 spring-cloud-starter-gateway 模块自动装配类中已经声明,可直接使用。RouteLocator 封装了对 Route 获取的定义,可简单理解成工厂模式。

② RouteLocatorBuilder 可以构建多个路由信息。

构建原理

GatewayProperties

GatewayProperties 是 Spring cloud gateway 模块提供的外部化配置类。

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

RouteDefinition

该组件用来对 Route 信息进行定义,最终会被 RouteLocator 解析成 Route。

 FilterDefinition

用来定义Filter。

@Validated
public class FilterDefinition {

	@NotNull
	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]);
		}
	}
           

PredicateDefinition

用于定义 Predicate。

RoutePredicateFactory

RoutePredicateFactory 是所有 predicate factory 的顶级接口,职责就是生产 Predicate。

创建一个用于配置用途的对象(config),以其作为参数应用到 

apply

方法上来生产一个 Predicate 对象,再将 Predicate 对象包装成 AsyncPredicate。

public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {

	/**
	 * Pattern key.
	 */
	String PATTERN_KEY = "pattern";

	// useful for javadsl
	default Predicate<ServerWebExchange> apply(Consumer<C> consumer) {
		C config = newConfig();
		consumer.accept(config);
		beforeApply(config);
		return apply(config);
	}

}
           

GatewayFilterFactory

GatewayFilterFactory 职责就是生产 GatewayFilter。

@FunctionalInterface
public interface GatewayFilterFactory<C> extends ShortcutConfigurable,
    Configurable<C> { // ①
    String NAME_KEY = "name";
    String VALUE_KEY = "value";

    GatewayFilter apply(C config); // ②
}
           

RouteLocator

 Route 的定位器或者说探测器,是用来获取 Route 信息的。

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

RouteDefinitionRouteLocator

RouteLocator 最主要的实现类,用于将 RouteDefinition 转换成 Route。

public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    private final RouteDefinitionLocator routeDefinitionLocator;
    private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
    private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>(); private final GatewayProperties gatewayProperties;
    private final SpelExpressionParser parser = new SpelExpressionParser();
    private BeanFactory beanFactory;
    private ApplicationEventPublisher publisher;

}
           

构造函数

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

构造函数依赖 4 个对象,分别是:

① RouteDefinition Locator,一个 RouteDefinitionLocator 对象。

② predicates factories,Predicate 工厂列表,会被映射成 

key

 为 name, 

value

 为 factory 的 Map。可以猜想出 gateway 是如何根据 PredicateDefinition 中定义的 

name

 来匹配到相对应的 factory 了。

③ filter factories,Gateway Filter 工厂列表,同样会被映射成 

key

 为 name, 

value

 为 factory 的 Map。

④ gateway properties,外部化配置类。

疑问:该类依赖 GatewayProperties 对象,后者已经携带了 List 结构的 RouteDefinition,那为什么还要依赖 RouteDefinitionLocator 来提供 RouteDefinition?

  1. 这里并不会直接使用到 GatewayProperties 类中的 RouteDefinition,仅是用到其定义的 default filters,这会应用到每一个 Route 上。
  2. 最终传入的 RouteDefinitionLocator 实现上是 CompositeRouteDefinitionLocator 的实例,它组合了 GatewayProperties 中所定义的 routes。

getRoutes()

@Override
	public Flux<Route> getRoutes() {
		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()  //获取 RouteDefinition
				.map(this::convertToRoute);  //转换成Route

......

		return routes.map(route -> {
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition matched: " + route.getId());
			}
			return route;
		});
	}
//将 RouteDefinition 转换成 Route。
	private Route convertToRoute(RouteDefinition routeDefinition) {
        //将 PredicateDefinition 转换成 AsyncPredicate。
		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
        //将 FilterDefinition 转换成 GatewayFilter。
		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
        //生成 Route 对象。
		return Route.async(routeDefinition).asyncPredicate(predicate)
				.replaceFilters(gatewayFilters).build();
	}
           
FilterDefinition 转换成 GatewayFilter
           
private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
		List<GatewayFilter> filters = new ArrayList<>();

		// TODO: support option to apply defaults after route specific filters?
        //获取gateway配置的默认的filters
		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
					this.gatewayProperties.getDefaultFilters()));
		}
        //获取每个route配置的 gatewayFilters
		if (!routeDefinition.getFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
					routeDefinition.getFilters()));
		}
        //排序
		AnnotationAwareOrderComparator.sort(filters);
		return filters;
	}
           

PredicateDefinition 转换成 AsyncPredicate

private AsyncPredicate<ServerWebExchange> combinePredicates(
			RouteDefinition routeDefinition) {
        //获取配置的route的predicate。
		List<PredicateDefinition> predicates = routeDefinition.getPredicates();
        //将列表中第一个 PredicateDefinition 转换成 AsyncPredicate。
		AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
				predicates.get(0));
        //循环调用,将列表中每一个 PredicateDefinition 都转换成 AsyncPredicate。
		for (PredicateDefinition andPredicate : predicates.subList(1,
				predicates.size())) {
			AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
					andPredicate);
            //应用and操作,将所有的 AsyncPredicate 组合成一个 AsyncPredicate 对象。
			predicate = predicate.and(found);
		}

		return predicate;
	}
           

lookup

private AsyncPredicate<ServerWebExchange> lookup(
    RouteDefinition route, PredicateDefinition predicate) {
//根据 predicate 名称获取对应的 predicate factory。
    RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
    if (factory == null) {
        throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name             " + predicate.getName());
    }
//获取 PredicateDefinition 中的 Map 类型参数,key 是固定字符串_genkey_ + 数字拼接而成。
    Map<String, String> args = predicate.getArgs();// 
    if (logger.isDebugEnabled()) {
        logger.debug("RouteDefinition " + route.getId() + " applying "
                     + args + " to " + predicate.getName());
    }
//对上 步获得的参数作进一步转换,key为 config 类(工厂类中通过范型指定)的属性名称。
    Map<String, Object> properties = factory.shortcutType().normalize(
        args, factory, this.parser, this.beanFactory);
//调用 factory 的 newConfig 方法创建一个 config 类对象。
    Object config = factory.newConfig();
//将上步中产生的参数绑定到 config 对象上。
    ConfigurationUtils.bind(config, properties,
                            factory.shortcutFieldPrefix(), predicate.getName(),                                     validator); 

    if (this.publisher != null) {
        this.publisher.publishEvent(
            new PredicateArgsEvent(this, route.getId(), properties));
    }
//将 cofing 作参数代入,调用 factory 的 applyAsync 方法创建 AsyncPredicate 对象。
    return factory.applyAsync(config); 
}
           

继续阅读