apo切面编程解决分布式限流

列如如下事咧:

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRedisLimiter {
@AliasFor(“limit”)
double value() default Double.MAX_VALUE;
double limit() default Double.MAX_VALUE;
}

@Aspect
@Component
public class MyRedisLimiterAspect {
private final Logger logger = LoggerFactory.getLogger(MyRedisLimiter.class);
@Autowired
private HttpServletResponse response;
@Autowired
private StringRedisTemplate stringRedisTemplate;
private DefaultRedisScript redisScript;
@PostConstruct
public void init(){
redisScript = new DefaultRedisScript();
redisScript.setResultType(List.class);
redisScript.setScriptSource(new ResourceScriptSource(new
ClassPathResource((“limit.lua”))));
}
@Pointcut(“execution(public * io.com.test.limiter.controller..(…))”)
public void pointcut(){
}
读取项目classpath目录下的limit.lua脚本文件来确定是否执行限流的操作,调用limit.lua文 件执行的结果返回0则表示执行限流逻辑,否则不执行限流逻辑。既然,项目中需要使用Lua脚本,那 么,接下来,我们就需要在项目中创建Lua脚本。
@Around(“pointcut()”)
public Object process(ProceedingJoinPoint proceedingJoinPoint) throws
Throwable{
MethodSignature signature = (MethodSignature)
proceedingJoinPoint.getSignature();
//使用反射获取MyRedisLimiter注解
MyRedisLimiter myRedisLimiter =
signature.getMethod().getDeclaredAnnotation(MyRedisLimiter.class);
if(myRedisLimiter == null){ //正常执行方法
return proceedingJoinPoint.proceed();
}
//获取注解上的参数,获取配置的速率
double value = myRedisLimiter.value(); //List设置Lua的KEYS[1]
String key = “ip:” + System.currentTimeMillis() / 1000; List keyList = Lists.newArrayList(key);
//List设置Lua的ARGV[1]
List argvList = Lists.newArrayList(String.valueOf(value));
//调用Lua脚本并执行
List result = stringRedisTemplate.execute(redisScript, keyList,
String.valueOf(value));
logger.info(“Lua脚本的执行结果:” + result);
//Lua脚本返回0,表示超出流量大小,返回1表示没有超出流量大小。 if(“0”.equals(result.get(0).toString())){
fullBack();
return null;
}
//获取到令牌
return proceedingJoinPoint.proceed();
}
private void fullBack() {
response.setHeader(“Content-Type” ,“text/html;charset=UTF8”);
PrintWriter writer = null;
try{
writer = response.getWriter(); writer.println(“回退失败,请稍后重试”); writer.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
if(writer != null){
} }
}

lua脚本
local key = KEYS[1] --限流KEY(一秒一个)
local limit = tonumber(ARGV[1]) --限流大小
local current = tonumber(redis.call(‘get’, key) or “0”) if current + 1 > limit then --如果超出限流大小
return 0
else --请求数+1,并设置2秒过期
redis.call(“INCRBY”, key, “1”)
redis.call(“expire”, key “2”)
return 1
end

你可能感兴趣的:(分布式,junit)