springboot中基于aop和semaphore实现api限流-kb88凯时官网登录

时间:2024-10-20
阅读:
免费资源网,https://freexyz.cn/

为了在 spring boot 中使用 aop 实现速率限制:

  • 定义自定义注释来标记应该限速的方法。
  • 创建一个方面类,拦截用自定义注释注释的方法调用。
  • 使用速率限制器组件来跟踪和执行速率限制。
  • 处理速率限制超出的情况,如通过抛出自定义异常。

spring boot api 中的速率限制

可以使用各种技术在 spring boot api 中实现速率限制。一种常见的方法是使用 spring aop来拦截传入的请求并实施速率限制。

步骤 1 - 定义速率限制配置

创建一个配置类,在其中定义速率限制参数,例如允许的请求数和时间段。

@configuration
public class ratelimitconfig {
    @value("${rate.limit.requests}")
    private int requests;
    @value("${rate.limit.seconds}")
    private int seconds;
    // getters and setters
}

步骤 2 - 创建速率限制方面

使用 spring aop 实现一个方面来拦截方法调用并强制执行速率限制。

@aspect
@component
public class ratelimitaspect {
    @autowired
    private ratelimitconfig ratelimitconfig;
    @autowired
    private ratelimiter ratelimiter;
    @around("@annotation(ratelimited)")
    public object enforceratelimit(proceedingjoinpoint joinpoint) throws throwable {
        string key = getkey(joinpoint);
        if (!ratelimiter.tryacquire(key, ratelimitconfig.getrequests(), ratelimitconfig.getseconds())) {
            throw new ratelimitexceededexception("rate limit exceeded");
        }
        return joinpoint.proceed();
    }
    private string getkey(proceedingjoinpoint joinpoint) {
        //为正在调用的方法生成唯一密钥
        //方法签名、用户id、ip地址等。
    }
}

步骤 3 — 定义 ratelimited 注释

创建自定义注释来标记应受速率限制的方法。

@target(elementtype.method)
@retention(retentionpolicy.runtime)
  public @interface ratelimited {
}

步骤 4 - 实施速率限制器

创建速率限制器组件,使用令牌桶算法或任何其他合适的算法来管理速率限制。

@component
public class ratelimiter {
    private final map semaphores = new concurrenthashmap<>();
    public boolean tryacquire(string key, int requests, int seconds) {
        
        long currenttime = system.currenttimemillis();
        // 计算时间窗口
        long starttime = currenttime - seconds * 1000;
        // 过期删除
        cleanupexpiredentries(starttime);
        // 获取semaphore 
        ratelimitedsemaphore semaphore = semaphores.computeifabsent(key, k -> {
            ratelimitedsemaphore newsemaphore = new ratelimitedsemaphore(requests);
            newsemaphore.setlastacquiretime(currenttime); // set last acquire time
            return newsemaphore;
        });
        // 校验 semaphore 
        boolean acquired = semaphore.tryacquire();
        if (acquired) {
            semaphore.setlastacquiretime(currenttime); 
            // 更新
        }
        return acquired;
    }
    private void cleanupexpiredentries(long starttime) {
        iterator> iterator = semaphores.entryset().iterator();
        while (iterator.hasnext()) {
            map.entry entry = iterator.next();
            string key = entry.getkey();
            ratelimitedsemaphore semaphore = entry.getvalue();
            if (semaphore.getlastacquiretime() < starttime) {
                iterator.remove();
            }
        }
    }
    private class ratelimitedsemaphore extends semaphore {
        private volatile long lastacquiretime;
        public ratelimitedsemaphore(int permits) {
            super(permits);
        }
        public long getlastacquiretime() {
            return lastacquiretime;
        }
        public void setlastacquiretime(long lastacquiretime) {
            this.lastacquiretime = lastacquiretime;
        }
    }
}

步骤 5 - 注释控制器方法

用注解来注释应该进行速率限制的控制器方法 @ratelimited。

@restcontroller
public class mycontroller {
    @ratelimited
    @getmapping("/api/resource")
    public responseentity getresource() {
        // implementation
    }
}

步骤 6 - 配置速率限制属性

application.properties在您的 或 中配置速率限制属性 application.yml。

rate.limit.requests=10
rate.limit.seconds=60

要按 ip 地址限制请求,可以从传入请求中提取 ip 地址并将其用作速率限制的密钥:

private string getkey(httpservletrequest request) {
    string ipaddress = request.getremoteaddr();
    return ipaddress; //用id做key
}

还需要修改enforceratelimit 中的方法 ratelimitaspect 以将对象传递 httpservletrequest 给 getkey 方法:

@around("@annotation(ratelimited)")
public object enforceratelimit(proceedingjoinpoint joinpoint) throws throwable {
   
    servletrequestattributes requestattributes = (servletrequestattributes) requestcontextholder.getrequestattributes();
    httpservletrequest request = requestattributes.getrequest();
    string key = getkey(request);
    if (!ratelimiter.tryacquire(key, ratelimitconfig.getrequests(), ratelimitconfig.getseconds())) {
        throw new ratelimitexceededexception("rate limit exceeded");
    }
    return joinpoint.proceed();
}

以上就是springboot中基于aop和semaphore实现api限流的详细内容,更多关于springboot实现api限流的资料请关注其它相关文章!

免费资源网,https://freexyz.cn/
返回顶部
顶部
网站地图