目录
前言
什么是限流?
实现限流
创建一个注解类
接着创建一个切面类
前言
在项目中,对于接口的限流,是任何项目都必不可少的一部分,主要是为了防止用户频繁的发送请求,对服务器造成压力。
另外一点就是防止外来攻击,对服务器也会造成压力,所以才衍生出了需要对接口进行限流访问的次数
什么是限流?
限流通俗来讲就是限制流量大小,这里的流量并不是指我们平常手机上的流量,这里的流量指的是,用户每一次刷新网页时对服务器发送一次请求,就是一次流量。
我们通过限流,来防止用户过多刷新网页,平常我们也会看到一些网页,发送验证码过多次数,他就会提示你请稍后再发送。
实现限流
我们这里使用springBoot的AOP切面编程,来对接口进行限流操作
创建一个注解类
我们先创建一个注解类,因为对于AOP切面编程来说,集成注解模式是最好的解决方案
这里定义了两个参数
一个允许被访问的次数,是自定义的
还有一个默认的60秒,是在一段时间内进行限流多少次
package com.sxy.recordnetwork.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 设置访问次数限制的注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {int count(); // 允许被访问的次数int seconds() default 60; // 时间范围,秒为单位,表示在60秒内访问的次数}
接着创建一个切面类
主要的逻辑就是,在标注了这个注解类AccessLimit的方法上执行的AOP切面,在方法执行之前
我们通过JoinPoint对象,获取到目标方法名,以方法名作为唯一的key
接着获取注解里的参数,为次数和时间
key为方法名:值为访问次数
对它进行一定的判断,然后每一次访问这个接口都会调用decrement这个方法,对key对应的值(访问次数)进行自减操作
package com.sxy.recordnetwork.aspect;import com.sxy.recordnetwork.Exception.Son.ApiRateLimitExceedException;
import com.sxy.recordnetwork.annotation.AccessLimit;
import com.sxy.recordnetwork.enumeration.Constants;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** 设置访问次数限制的AOP切面*/
@Aspect
@Component
@Slf4j
public class AccessLimitAspect {@Autowired // redisprivate RedisTemplate redisTemplate;// 添加一个前置通知,在方法执行之前执行 切入点为满足添加了这个AccessLimit注解的方法@Before("@annotation(accessLimit)")public void AccessLimitBefore(JoinPoint joinPoint, AccessLimit accessLimit) {// 获取注解的属性// 通过joinPoint获取目标方法名String methodName = joinPoint.getSignature().getName();// 设置一下redis的访问ValueOperations valueOperations = redisTemplate.opsForValue();// 获取注解属性Integer count = accessLimit.count(); // 访问次数int seconds = accessLimit.seconds(); // 在一定时间内// 设置初始值,如果不存在则设置,存在则不设置,返回一个boolean,设置了就为true,否则是falseBoolean isNew = valueOperations.setIfAbsent(methodName, count - 1, seconds, TimeUnit.SECONDS);// 判断是旧的keyif (!isNew) {// 如果键存在,获取当前值并且递减Integer currentCount = (Integer) valueOperations.get(methodName);// 次数小于等于0就是访问次数超出限制if (currentCount != null && currentCount <= 0) {throw new ApiRateLimitExceedException(Constants.FREQUENT_VISITS.getValue());} else {// 递减valueOperations.decrement(methodName, 1);}}}
}
在控制层就这么添加注解,count就是访问的次数
这样就实现了一个简单的对接口进行限流
以上就是今天分享的内容,对接口进行限流,如有问题,欢迎在下方评论区留言,感谢大家的支持,给个三连呗~🍒
欢迎大家关注我的微信公众号,里面分享了更多的开发技巧