要搞清楚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;
}
}