Spring Cloud Gateway源码分析:GatewayFilter的加载机制

要搞清楚GatewayFilter的加载流程得用剥洋葱方式,一层一层深入进去,特别绕。其实我只是想看看GatewayFilterFactory是如何生成GatewayFilter的,一般的逻辑是加载完filter的配置就立刻生成GatewayFilter。但是SCG是在组装route属性的时候才生成GatewayFilter。我们从读取配置文件的方式来理解GatewayFilter的加载,其加载涉及的类和方法如下,
在这里插入图片描述

1. GatewayProperties加载配置文件

SCG加载route文件的类是GatewayProperties,我们可以看到里面定义了RouteDefinition和FilterDefinition,其结构对应以下配置:

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - AddRequestHeader=X-Request-Red, Blue-{segment}

代码结构如下

@ConfigurationProperties(GatewayProperties.PREFIX)
@Validated
public class GatewayProperties {

	/**
	 * 属性的前缀,跟上面配置一致.
	 */
	public static final String PREFIX = "spring.cloud.gateway";
	/**
	 * route列表,spring boot机制会自动把配置文件的属性装配进来
	 */
	@NotNull
	@Valid
	private List<RouteDefinition> routes = new ArrayList<>();

	/**
	 * 一个route对应一个filter列表,spring boot机制会自动把配置文件的属性装配进来
	 */
	private List<FilterDefinition> defaultFilters = new ArrayList<>();

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

// route定义类
@Validated
public class RouteDefinition {

	private String id;

	@NotEmpty
	@Valid
	// 断言列表
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
	// filter列表
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
	// 路由的uri
	private URI uri;

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

	private int order = 0;

	public RouteDefinition() {
	}
	
	// 这里会把配置中predicate等号两边分割为key-value的map,是为了跟GatewayPredicate做匹配,
	// 通过key找到对应RoutePredicateFactory,然后生成GatewayPredicate
	public RouteDefinition(String text) {
		// 代码省略
	}

@Validated
public class FilterDefinition {

	@NotNull
	private String name;

	private Map<String, String> args = new LinkedHashMap<>();

	public FilterDefinition() {
		System.out.println("");
	}

	// 这里会把配置中filter等号两边分割为key-value的map,是为了跟GatewayFilterFactory做匹配,
	// 通过key找到对应GatewayFilterFactory,然后生成GatewayFilter
	public FilterDefinition(String text) {
		// 代码省略
	}

	public String getName() {
		return name;
	}

通过上面的配置文件的加载,我们并没有看到GatewayFilter相关的信息,所以我们还得继续往下找。

2.查看FilteringWebHandler获取filter逻辑

第二步我们再看看FilteringWebHandler#handle的处理逻辑,他可以从route里拿到所有的GatewayFilter,我们可以从这里找到一些信息

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		// 遗憾的是,这里直接从route拿GatewayFilter了,我们看不到GatewayFilter是如何被创建的
		List<GatewayFilter> gatewayFilters = route.getFilters();

		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		// TODO: needed or cached?
		AnnotationAwareOrderComparator.sort(combined);

		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}

		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}

3.查看RoutePredicateHandlerMapping的加载

我们可以想象,一个请求进来处理过后,GatewayFilter肯定是会被创建的,我们顺着这个思路看看RoutePredicateHandlerMapping是如何做路由转发的,首先从他的加载入手,从GatewayAutoConfiguration的类中看看相关bean的加载:

	@Bean
	@ConditionalOnMissingBean
	// 这里会把第一步讲解的GatewayProperties注入进来,就可以使用配置文件读取到的属性了
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
			GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}
	// 入参routeDefinitionLocator就是上面propertiesRouteDefinitionLocator方法加载bean
	@Bean
	public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
			List<GatewayFilterFactory> gatewayFilters,
			List<RoutePredicateFactory> predicates,
			RouteDefinitionLocator routeDefinitionLocator,
			ConfigurationService configurationService) {
		// 这个bean就是后面调getRoutes()的bean
		return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
				gatewayFilters, properties, configurationService);
	}

	@Bean
	// 加了Primary主,同类型首先会注入这个bean
	@Primary
	@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
	public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
		// 这里是route信息的缓存对象,里面的逻辑可以看到GatewayFilter的创建
		return new CachingRouteLocator(
				new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
	}		

4.CachingRouteLocator类

public class CachingRouteLocator implements Ordered, RouteLocator,
		ApplicationListener<RefreshRoutesEvent>, ApplicationEventPublisherAware {
	public CachingRouteLocator(RouteLocator delegate) {
		this.delegate = delegate;
		// 构造器里会执行这个方法,把routes加载到缓存,首先调用fetch方法,
		routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
				.onCacheMissResume(this::fetch);
	}

	private Flux<Route> fetch() {
		// 这里最终调用的是RouteDefinitionRouteLocator#getRoutes,我们可以进入这个类看看
		return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
	}
}

public class RouteDefinitionRouteLocator
		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
		/**这里省略部分代码
		*/ 
	// RouteDefinitionRouteLocator#getRoutes会调loadGatewayFilters
	List<GatewayFilter> loadGatewayFilters(String id,
			List<FilterDefinition> filterDefinitions) {
		ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
		for (int i = 0; i < filterDefinitions.size(); i++) {
			FilterDefinition definition = filterDefinitions.get(i);
			// 从这里可以看到拿到了GatewayFilterFactory
			GatewayFilterFactory factory = this.gatewayFilterFactories
					.get(definition.getName());
			
			// 省略部分代码
			// 从这里可以看到factory创建GatewayFilter,假如是AddRequestHeaderGatewayFilterFactory,则会调用下面截图的方法apply()
			GatewayFilter gatewayFilter = factory.apply(configuration);
			if (gatewayFilter instanceof Ordered) {
				ordered.add(gatewayFilter);
			}
			else {
				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
			}
		}
		return ordered;
	}
}	

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Gateway 是一个基于 Spring Framework 5、Spring Boot 2 和 Project Reactor 的 API 网关服务。它提供了一种简单而强大的方法来路由和过滤请求,并将它们转发到底层的微服务。对于理解 Spring Cloud Gateway 的工作原理和深入研究其源代码是非常有用的。 首先,通过源码可以发现 Spring Cloud Gateway 主要由三个核心模块组成:路由模块、过滤器模块和事件模块。路由模块负责根据定义的路由规则将请求转发到特定的目标地址。过滤器模块负责在请求的不同阶段执行一系列的过滤器来处理请求。事件模块则用于处理与路由和过滤器相关的异步事件。 源码中的路由模块使用了 Reactive Streams API 中的 Flux 和 Mono 类来处理异步操作。它利用 RouterFunction 和 HandlerFunction 来定义路由和处理请求的方法,并通过 RoutePredicateFactory 来解析和匹配路由规则。在路由模块中,使用了 Netty 库来实现底层的网络通信和请求转发。 通过源码分析过滤器模块,可以发现 Spring Cloud Gateway 的过滤器分为全局过滤器和自定义过滤器两种类型。全局过滤器在请求的全局范围内应用,并且可以用于添加一些全局的处理逻辑。自定义过滤器则允许开发者根据需要添加自定义的过滤逻辑。过滤器的执行顺序可以通过 Order 注解来控制,以满足不同过滤器的执行顺序需求。 事件模块在源码中使用了 Reactor 提供的 EventProcessor 来处理与路由和过滤器相关的事件。它使用了 Reactor 的 FluxSink 和 MonoSink 来创建异步事件源,并通过事件处理器将事件发送给注册的监听器。通过查看事件模块的源码,可以更加深入地了解 Spring Cloud Gateway 是如何处理与路由和过滤器相关的事件的。 总结而言,通过源码分析 Spring Cloud Gateway,我们可以更好地了解其内部的工作原理和实现细节。这对于开发者来说是非常有用的,因为它可以帮助我们更好地使用和扩展 Spring Cloud Gateway 来满足不同的场景需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值