• SpringCloud GateWay自定义过滤器之GatewayFilter和AbstractGatewayFactory


    一、GatewayFilter

    GatewayFilter 是一个简单的接口,用于定义网关过滤器的行为。一个网关过滤器就是一个实现了 GatewayFilter 接口的类,它可以执行在请求进入网关或响应离开网关时的某些操作。过滤器可以用于修改请求或响应,记录日志,添加头部信息,等等。

    1. public interface GatewayFilter {
    2. Mono filter(ServerWebExchange exchange, GatewayFilterChain chain);
    3. }

    一个简单的自定义网关过滤器,:

    1. public class MyFilter implements GatewayFilter, Ordered {
    2. @Override
    3. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    4. exchange.getAttributes().put("start",System.currentTimeMillis());
    5. return chain.filter(exchange).then(Mono.fromRunnable(new Runnable() {
    6. @Override
    7. public void run() {
    8. long start = exchange.getAttribute("start");
    9. System.out.println(exchange.getRequest().getURI() + "执行耗时:" + (System.currentTimeMillis()-start));
    10. }
    11. }));
    12. }
    13. @Override
    14. public int getOrder() {
    15. return 0;
    16. }
    17. }

    配置:

    1. @Configuration
    2. public class MyConfig {
    3. /**配置自定义过滤器*/
    4. @Bean
    5. public RouteLocator routeLocator(RouteLocatorBuilder builder) {
    6. return builder.routes().route(r ->
    7. r.path("/provider/**")//用户访问的路径
    8. .uri("lb://service-provider")//路由的真实服务器ip+端口
    9. .filters(new MyFilter()) // 局部过滤器
    10. .id("provider_route")) // 路由id
    11. .build();
    12. }
    13. }

    二、AbstractGatewayFilterFactory

    AbstractGatewayFilterFactory 是一个抽象类,用于更方便地创建网关过滤器。它处理过滤器的参数解析和创建,使得定义过滤器变得更加简单。

    1. public class MyCustomGatewayFilterFactory extends AbstractGatewayFilterFactory {
    2. public MyCustomGatewayFilterFactory() {
    3. super(Config.class);
    4. }
    5. @Override
    6. public GatewayFilter apply(Config config, Class configClass) {
    7. // 在这里创建并返回过滤器实例
    8. return (exchange, chain) -> {
    9. // 过滤器逻辑
    10. return chain.filter(exchange);
    11. };
    12. }
    13. public static class Config {
    14. // 过滤器的配置参数
    15. }
    16. }

    下面是一个通过令牌桶算法实现的简单限流:

    1. import org.springframework.cloud.gateway.filter.GatewayFilter;
    2. import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class RateLimitByIpGatewayFilterFactory extends AbstractGatewayFilterFactory {
    6. public RateLimitByIpGatewayFilterFactory() {
    7. super(Config.class);
    8. }
    9. @Override
    10. public GatewayFilter apply(Config config) {
    11. return (exchange, chain) -> {
    12. // 获取请求的IP地址
    13. String ipAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
    14. // 使用简单的基于IP的限流逻辑,你可以根据实际需求选择其他限流算法
    15. // 这里使用一个简单的令牌桶算法作为示例
    16. if (isRateLimited(ipAddress, config.getLimit())) {
    17. // 如果超过限流阈值,返回错误响应
    18. exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
    19. return exchange.getResponse().setComplete();
    20. }
    21. // 如果未超过限流阈值,继续处理请求
    22. return chain.filter(exchange);
    23. };
    24. }
    25. private boolean isRateLimited(String ipAddress, int limit) {
    26. // 在这里实现你的限流逻辑,这里使用一个简单的令牌桶算法作为示例
    27. // 你可以使用库如Google Guava RateLimiter来简化实现
    28. // 这里只是一个简单的示例,请根据实际需求进行更复杂的实现
    29. // 在真实场景中,你可能需要将访问频率记录到数据库或分布式缓存中
    30. // 这里使用一个简单的Map模拟存储令牌桶
    31. Map tokenBucket = new ConcurrentHashMap<>();
    32. // 获取当前时间戳
    33. long now = System.currentTimeMillis();
    34. // 获取或初始化令牌桶
    35. tokenBucket.putIfAbsent(ipAddress, now);
    36. // 获取上次访问时间
    37. long lastAccessTime = tokenBucket.get(ipAddress);
    38. // 计算时间间隔
    39. long interval = now - lastAccessTime;
    40. // 计算令牌生成速率
    41. double rate = 1000.0 / limit; // 假设限制每秒请求次数
    42. // 计算应该生成的令牌数量
    43. int tokensToAdd = (int) (interval / rate);
    44. // 更新令牌桶中的令牌数量
    45. tokenBucket.put(ipAddress, now + tokensToAdd);
    46. // 检查令牌数量是否超过阈值
    47. return tokensToAdd > limit;
    48. }
    49. public static class Config {
    50. private int limit;
    51. public int getLimit() {
    52. return limit;
    53. }
    54. public void setLimit(int limit) {
    55. this.limit = limit;
    56. }
    57. }
    58. }

    配置文件配置限流阈值:

    1. spring:
    2. cloud:
    3. gateway:
    4. routes:
    5. - id: rate_limit_route
    6. uri: http://example.com
    7. filters:
    8. - RateLimitByIp=1
    9. predicates:
    10. - Path=/api/**

    上述配置将限制 /api/** 路径下的请求每秒只能有 1 次。请注意,RateLimitByIp 需要和 RateLimitByIpGatewayFilterFactory 的类名中的大小写一致,同时参数 1 是用来设置限流的阈值,你可以根据需要调整。 

    1. 固定容量的令牌桶: 令牌桶内有固定数量的令牌,这些令牌以固定的速率被添加到桶中。

    2. 令牌添加速率: 令牌以恒定的速率(例如每秒添加固定数量的令牌)被添加到令牌桶中。

    3. 令牌消耗: 当请求到达时,需要从令牌桶中获取一个令牌。如果令牌桶中有足够的令牌,则请求被允许处理,并消耗一个令牌;否则,请求被限流。

    4. 平滑限流: 由于令牌以恒定速率被添加,令牌桶算法可以实现平滑限流,即请求被均匀地处理,而不是突然被拒绝。

    5. 适应突发流量: 令牌桶算法对于处理突发流量也具有一定的适应性,因为即使令牌桶空了一段时间,一旦有令牌被添加,就可以处理新的请求。

    6. 容错性好: 由于令牌桶算法是基于时间的,因此对于时间敏感的应用来说,容错性较好。而且由于每个请求都需要从令牌桶中获取令牌,因此可以有效防止突发请求对系统的影响。

     

    三、区别

    1. 设计用途:

    • GatewayFilter: 用于定义网关过滤器的行为,是一个简单的接口。每个过滤器的实现需要直接实现 GatewayFilter 接口中的方法。
    • AbstractGatewayFilterFactory: 是一个抽象类,旨在更方便地创建具有配置参数的网关过滤器。通过继承这个抽象类,你可以更容易地处理配置参数的解析和过滤器实例的创建。
    1. 用法:

    • GatewayFilter: 直接实现 GatewayFilter 接口,编写过滤器逻辑。这种方式适用于不需要配置参数的简单过滤器。
    • AbstractGatewayFilterFactory: 继承该抽象类,实现抽象方法 applyapply(C config, Class configClass),并在其中处理配置参数并创建过滤器实例。这种方式适用于需要配置参数的过滤器。
    1. 配置参数:

    • GatewayFilter: 如果过滤器需要配置参数,需要通过其他方式(如构造函数、属性注入等)传递参数,因为 GatewayFilter 接口本身不提供直接的配置机制。
    • AbstractGatewayFilterFactory: 通过泛型参数 C 指定配置参数的类型,并在 apply 方法中接收配置参数。这使得配置参数的处理更为灵活,Spring Cloud Gateway 会负责将配置参数绑定到过滤器实例。
  • 相关阅读:
    Pytorch房价预测
    Dubbo入门实战最全攻略(基于 Spring Boot 实现)
    ElementPlus·面包屑导航实现
    quickapp_快应用_tabBar
    Jenkins实现基础CI操作
    DBCO-PA-PA-Mal
    【神经网络】基于自注意力机制的深度学习
    数据结构与算法——绪论
    大数据与云计算
    vue中sync修饰符
  • 原文地址:https://blog.csdn.net/Candy___i/article/details/134398663