Skip to content

Spring Cloud 教程 - Spring Cloud Gateway动态路由实现 #11

@TFdream

Description

@TFdream

Spring Cloud Gateway配置路由主要有两种方式:一种是用yml配置文件,一种是写代码里,这两种方式都是不支持动态配置的。

现实生产环境中,使用Spring Cloud Gateway都是作为所有流量的入口,为了保证系统的高可用,尽量避免系统的重启,所以需要Spring Cloud Gateway的动态路由来处理。

首先我们来看看gateway是如何加载这些配置信息的。

注:本篇 Spring Boot版本为 2.3.0.RELEASE,Spring Cloud版本为Hoxton.SR5,spring-cloud-gateway版本为2.2.3.RELEASE。

1、路由初始化

无论是yml还是代码配置,这些配置最终都是被封装到RouteDefinition对象中,如下:

package org.springframework.cloud.gateway.route;

/**
 * @author Spencer Gibb
 */
@Validated
public class RouteDefinition {

	private String id;

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

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

	@NotNull
	private URI uri;

	private Map<String, Object> metadata = new HashMap<>();

	private int order = 0;

	public RouteDefinition() {
	}

一个RouteDefinition有个唯一的ID,如果不指定,就默认是UUID,多个RouteDefinition组成了gateway的路由系统。

所有路由信息在系统启动时就被加载装配好了,并存到了内存里,这点我们从 org.springframework.cloud.gateway.config.GatewayAutoConfiguration 类可以看出,如下:

/**
 * @author Spencer Gibb
 * @author Ziemowit Stolarczyk
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
		WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayLoadBalancerClientAutoConfiguration.class,
		GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {

	@Bean
	public StringToZonedDateTimeConverter stringToZonedDateTimeConverter() {
		return new StringToZonedDateTimeConverter();
	}

	@Bean
	public RouteLocatorBuilder routeLocatorBuilder(
			ConfigurableApplicationContext context) {
		return new RouteLocatorBuilder(context);
	}

	//yml文件中配置的路由信息
	@Bean
	@ConditionalOnMissingBean
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
			GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}

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

	@Bean
	@Primary
	public RouteDefinitionLocator routeDefinitionLocator(
			List<RouteDefinitionLocator> routeDefinitionLocators) {
		return new CompositeRouteDefinitionLocator(
				Flux.fromIterable(routeDefinitionLocators));
	}

	@Bean
	@Primary
	@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
	// TODO: property to disable composite?
	public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
		return new CachingRouteLocator(
				new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
	}

	@Bean
	public RouteRefreshListener routeRefreshListener(
			ApplicationEventPublisher publisher) {
		return new RouteRefreshListener(publisher);
	}
}

PropertiesRouteDefinitionLocator 就是 我们在yml文件中装配的路由信息,该类继承了RouteDefinitionLocator,RouteDefinitionLocator就是路由的装载器,里面只有一个方法,就是获取路由信息的。

RouteDefinitionLocator接口有多个实现类,分别对应不同方式配置的路由方式,
image

比较关键的几个如下:

  • CachingRouteDefinitionLocator:为RouteDefinitionLocator类提供缓存功能;
  • CompositeRouteDefinitionLocator:组合多种RouteDefinitionLocator实现;
  • PropertiesRouteDefinitionLocator:从配置文件(例如 YML / properties 等)读取RouteDefinition;
  • DiscoveryClientRouteDefinitionLocator:从注册中心(例如 Eureka、Consul、Nacos、Zookeeper等)读取RouteDefinition;

通过这几个实现类,再结合上面的AutoConfiguration里面的Primary信息,就知道加载配置信息的顺序。

PropertiesRouteDefinitionLocator-->|配置文件加载初始化| CompositeRouteDefinitionLocator
RouteDefinitionRepository-->|存储器中加载初始化| CompositeRouteDefinitionLocator
DiscoveryClientRouteDefinitionLocator-->|注册中心加载初始化| CompositeRouteDefinitionLocator

相关资料

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions