准备工作
1.了解lua语言的基本类型、语法、简单函数等(学习一下)
2.搭建redis集群环境redis-cli 3.2.11
3.自定义注解以及切面配置拦截器
1.项目配置
<!-- spring切面 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!-- jedisCluster -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.1.1</version>
</dependency>
2.限流注解配置
限流注解支持配置时间段(限流需要统计的时间片段)、水流速率(漏桶算法中的水流速、令牌桶算法中的生成令牌速率)、最大访问数(限流阀值)、限流方式(目前支持自定义key和IP,部分代码没贴出来,我把git地址贴在文章最后,有需要可以看一下)、自定义key(需要限流的key,支持spel表达式)、限流算法(本篇文章主要讲市面上主流的几种算法:滑动窗口、漏桶算法、令牌桶算法)
package com.dubbo.core.flowcontrol;
import com.dubbo.core.flowcontrol.enums.AlgorithmEnum;
import com.dubbo.core.flowcontrol.enums.FlowControlEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 限流
* @author lizixiang
* @since 2022/4/8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface FlowControl {
/**
* 时间段(s)
*/
long duration() default 60;
/**
* 水流速率(/s)
*/
int flowRate() default 1;
/**
* 最大访问数
*/
int max() default 1000;
/**
* 限流方式
*/
FlowControlEnum[] method() default FlowControlEnum.IP;
/**
* 自定义key
*/
String key() default "" ;
/**
* 限流算法
*/
AlgorithmEnum algorithm() default AlgorithmEnum.SLIDE_WINDOW;
}
3.配置切面
注解的参数不是所有都用到,后面会仔细讲解,切面主要就是对注解参数的解析再封装,我这里只写了自定义key,获取IP的方式各个公司都不一样,这里就不贴出来了。最后一句代码用到了自定义工厂类和策略模式的组合,不同的算法写到了指定的策略类当中,看不懂的同学自行百度学习一下。
strategy.flowControl(dto);
package com.dubbo.core.flowcontrol;
import com.dubbo.core.flowcontrol.enums.AlgorithmEnum;
import com.dubbo.core.flowcontrol.enums.FlowControlEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author lizixiang
* @since 2022/4/8
*/
@Aspect
@Component
public class FlowControlAspect {
private static final Logger logger = LoggerFactory.getLogger(FlowControlAspect.class);
@Pointcut("@annotation(com.dubbo.core.flowcontrol.FlowControl)")
public void flowControl() {
}
@Before(value = "flowControl()")
public void before(JoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
FlowControl flowControl = method.getAnnotation(FlowControl.class);
String key = flowControl.key();
AlgorithmEnum algorithm = flowControl.algorithm();
FlowControlEnum[] enums = flowControl.method();
long duration &#