SpringCloud Gateway——路由过滤器GatewayFilter

SpringCloud Gateway——路由过滤器GatewayFilter

1. 简介

Gateway分为全局过滤器GlobalFilter和局部过滤器GatewayFilter,局部过滤器只有在路由配置中针对路由ID配置了才会使用,对应配置中的filters属性。

如:

spring:
  application:
    name: nacos-gateway
  cloud:
    gateway:
      routes:
        - id: app
          uri: lb://nacos-app
          predicates:
            - Path=/app/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 10
                key-resolver: "#{@routeIdKeyResolver}"

接下来通过源码来分析局部过滤器的实现原理。

2. 源码分析

1. GatewayFilterFactory

Gateway内置的路由过滤器实现往往很少直接实现GatewayFilter接口,而是通过GatewayFilterFactory这个工厂类生成。这里以上篇限流文章中的RequestRateLimiterGatewayFilterFactory为例

RequestRateLimiterGatewayFilterFactory

@SuppressWarnings("unchecked")
@Override
public GatewayFilter apply(Config config) {
    KeyResolver resolver = getOrDefault(config.keyResolver, defaultKeyResolver);
    RateLimiter<Object> limiter = getOrDefault(config.rateLimiter,
                                               defaultRateLimiter);
    boolean denyEmpty = getOrDefault(config.denyEmptyKey, this.denyEmptyKey);
    HttpStatusHolder emptyKeyStatus = HttpStatusHolder
        .parse(getOrDefault(config.emptyKeyStatus, this.emptyKeyStatusCode));

    // 调用KeyResolver.resolve()解析出限流的维度
    return (exchange, chain) -> resolver.resolve(exchange).defaultIfEmpty(EMPTY_KEY)
        .flatMap(key -> {
            // 没找到则通过过滤器
            if (EMPTY_KEY.equals(key)) {
                if (denyEmpty) {
                    setResponseStatus(exchange, emptyKeyStatus);
                    return exchange.getResponse().setComplete();
                }
                return chain.filter(exchange);
            }
            String routeId = config.getRouteId();
            if (routeId == null) {
                Route route = exchange
                    .getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
                routeId = route.getId();
            }
            // 调用RateLimiter.isAllowed()判断是否允许访问
            return limiter.isAllowed(routeId, key).flatMap(response -> {

                // 返回的response中的header加入到exchange header中
                for (Map.Entry<String, String> header : response.getHeaders()
                     .entrySet()) {
                    exchange.getResponse().getHeaders().add(header.getKey(),
                                                            header.getValue());
                }

                // 允许访问则通过过滤器
                if (response.isAllowed()) {
                    return chain.filter(exchange);
                }

                // 被限流,返回HTTP状态码429
                setResponseStatus(exchange, config.getStatusCode());
                return exchange.getResponse().setComplete();
            });
        });
}

GatewayFilterFactoryapply()是用来生成GatewayFilter的,所以可以看到RequestRateLimiterGatewayFilterFactoryapply()定义了限流逻辑的GatewayFilter,那为什么是apply()呢?接着往下看

内置的GatewayFilterFactory实现都是在哪里实例化的呢?

GatewayAutoConfiguration:实例化了所有内置GatewayFilterFactory实现

@Bean
@ConditionalOnBean({ RateLimiter.class, KeyResolver.class })
public RequestRateLimiterGatewayFilterFactory requestRateLimiterGatewayFilterFactory(
    RateLimiter rateLimiter, KeyResolver resolver) {
    return new RequestRateLimiterGatewayFilterFactory(rateLimiter, resolver);
}

@Bean
public RewritePathGatewayFilterFactory rewritePathGatewayFilterFactory() {
    return new RewritePathGatewayFilterFactory();
}

@Bean
public RetryGatewayFilterFactory retryGatewayFilterFactory() {
    return new RetryGatewayFilterFactory();
}

@Bean
public SetPathGatewayFilterFactory setPathGatewayFilterFactory() {
    return new SetPathGatewayFilterFactory();
}

有了GatewayFilterFactory中定义的路由过滤器,在哪里使用到他们的呢?

2. RouteDefinitionRouteLocator

RouteDefinitionRouteLocator是路由解析器,将路由定义转换为Route对象,其中需要解析路由配置中定义的过滤器,这里就用到了GatewayFilterFactory.

RouteDefinitionRouteLocator

@Override
public Flux<Route> getRoutes() {
    Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
        .map(this::convertToRoute);

    if (!gatewayProperties.isFailOnRouteDefinitionError()) {
        // instead of letting error bubble up, continue
        routes = routes.onErrorContinue((error, obj) -> {
            if (logger.isWarnEnabled()) {
                logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
                            + " will be ignored. Definition has invalid configs, "
                            + error.getMessage());
            }
        });
    }

    return routes.map(route -> {
        if (logger.isDebugEnabled()) {
            logger.debug("RouteDefinition matched: " + route.getId());
        }
        return route;
    });
}

private Route convertToRoute(RouteDefinition routeDefinition) {
    AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
    List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);

    return Route.async(routeDefinition).asyncPredicate(predicate)
        .replaceFilters(gatewayFilters).build();
}

@SuppressWarnings("unchecked")
List<GatewayFilter> loadGatewayFilters(String id,
                                       List<FilterDefinition> filterDefinitions) {
    // 过滤器定义转为GatewayFilter
    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());
        if (factory == null) {
            throw new IllegalArgumentException(
                "Unable to find GatewayFilterFactory with name "
                + definition.getName());
        }
        if (logger.isDebugEnabled()) {
            logger.debug("RouteDefinition " + id + " applying filter "
                         + definition.getArgs() + " to " + definition.getName());
        }

        // 构造Config
        Object configuration = this.configurationService.with(factory)
            .name(definition.getName())
            .properties(definition.getArgs())
            .eventFunction((bound, properties) -> new FilterArgsEvent(
                RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
            .bind();

        if (configuration instanceof HasRouteId) {
            HasRouteId hasRouteId = (HasRouteId) configuration;
            hasRouteId.setRouteId(id);
        }

        // 调用GatewayFilterFactory.apply()生成GatewayFilter
        GatewayFilter gatewayFilter = factory.apply(configuration);
        if (gatewayFilter instanceof Ordered) {
            ordered.add(gatewayFilter);
        }
        else {
            ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
        }
    }

    return ordered;
}

这里就用到了GatewayFilterFactory.apply().

根据名称筛选出GatewayFilterFactory实现是怎么做的呢?也就是怎样根据配置中的RequestRateLimiter找到RequestRateLimiterFactory

filters:
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10
      redis-rate-limiter.burstCapacity: 10
      key-resolver: "#{@routeIdKeyResolver}"

首先要看RouteDefinitionRouteLocator.gatewayFilterFactories的初始化,

GatewayAutoConfiguration

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
                                                List<GatewayFilterFactory> gatewayFilters,
                                                List<RoutePredicateFactory> predicates,
                                                RouteDefinitionLocator routeDefinitionLocator,
                                                ConfigurationService configurationService) {
    return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
                                           gatewayFilters, properties, configurationService);
}

RouteDefinitionRouteLocator

private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

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

将之前实例化GatewayFilterFactory的Bean集合按GatewayFilterFactory.name()为key,Bean为value加入到gatewayFilterFactories.

GatewayFilterFactory.name()

default String name() {
    return NameUtils.normalizeFilterFactoryName(getClass());
}

NameUtils

public static String normalizeFilterFactoryName(
    Class<? extends GatewayFilterFactory> clazz) {
    // 去掉类名中的GatewayFilterFactory
    return removeGarbage(clazz.getSimpleName()
                         .replace(GatewayFilterFactory.class.getSimpleName(), ""));
}

private static String removeGarbage(String s) {
    int garbageIdx = s.indexOf("$Mockito");
    if (garbageIdx > 0) {
        return s.substring(0, garbageIdx);
    }

    return s;
}

SO,这里通过去掉类名中的GatewayFilterFactory,对应上配置中的名称。



世界那么大,感谢遇见,未来可期…

欢迎同频共振的那一部分人

作者公众号:Tarzan写bug

你可能感兴趣的:(spring,cloud,gateway,java)