1.限流锁的应用场景
同一时间接口访问量巨大,如秒杀,需要进行限流。
2.实现思路
用 CURRENT_LIMIT_+ 类名+方法名作为redis的key, value作为访问秒杀接口的人数。
用redis的计数器统计访问人数,每新增一个访问请求,计数器+1,当人数超过上限,提示服务忙,秒杀接口处理完之后,计数器-1。
3.主要组成
Dcl
:限流注解,自定义锁注解,然后给需要限流的方法加上此注解
DistributedCurrentLimit
:限流接口
RedisDistributedCurrentLimit
:限流实现类
DistributedCurrentLimitAspect
:切面类【核心】
自定义锁注解,利用切面给所有加注解的方法加分布式锁进行限流。
4.关键代码分析:
DistributedCurrentLimitAspect
:用redis计时器算人头,人头达到上限就返回服务正忙
@Around("@annotation(com.nascent.ecrp.mall.common.distribute.Dcl)")
public Object distributedLock(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
if (request == null) {
return proceedingJoinPoint.proceed();
}
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
// 用CURRENT_LIMIT_+ 类名+方法名作为redis的key,统计调用此方法的用户数
String lockKey = "CURRENT_LIMIT_" + method.getDeclaringClass().getName() + "." + method.getName();
Dcl distributedKey = method.getAnnotation(Dcl.class);
// 解析缓存key的后缀
int keyIndex = distributedKey.keyIndex();
String suffixKey = "";
if (keyIndex > -1) {
Object[] args = proceedingJoinPoint.getArgs();
suffixKey += "_" + args[keyIndex];
}
lockKey += suffixKey;
try {
// 每进来一个,redis的计数器+1
Long incr = currentLimit.incr(lockKey);
// 计数器数 > MAX_LIMIT,抛出异常,用户就不能继续访问接口了
if (incr > MAX_LIMIT) {
// currentLimit.decr(lockKey);
throw new WmDefinitelyRuntimeException("前方道路拥挤,请稍后再试");
}
return proceedingJoinPoint.proceed();
} catch (Throwable e) {
throw new WmDefinitelyRuntimeException(e);
} finally {
currentLimit.decr(lockKey);
}
}
3.全部代码
Dcl
/**
* 限流
*/
@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dcl {
/**
* 缓存key后缀参数所在位置
*
* @return 位置
*/
int keyIndex();
}
DistributedCurrentLimit
/**
* 分布式限流
*/
public interface DistributedCurrentLimit{
/**
* 队列加1
*/
Long incr(String lockKey);
/**
* 队列减一
*/
Long decr(String lockKey);
RedisDistributedCurrentLimit
/**
* redis 分布式锁
*/
@SuppressWarnings({
"UnusedReturnValue", "NullableProblems", "unused", "RedundantThrows"})
@Component
public class RedisDistributedCurrentLimit implements DistributedCurrentLimit {
/**
* 缓存
*/