Java Redisson多策略注解限流

Java Redisson多策略注解限流

目录

前言

自定义注解

定义限流类型

生成key的工具类

定义aop具体逻辑

前言

限流:使用Redisson的RRateLimiter进行限流多策略:map+函数式接口优化if判断

限流:使用Redisson的RRateLimiter进行限流

多策略:map+函数式接口优化if判断

自定义注解 /** * aop限流注解 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface RedisLimit { String prefix() default "rateLimit:"; //限流唯一标示 String key() default ""; //限流单位时间(单位为s) int time() default 1; //单位时间内限制的访问次数 int count(); //限流类型 LimitType type() default LimitType.CUSTOM; } 定义限流类型 public enum LimitType { /** * 自定义key */ CUSTOM, /** * 请求者IP */ IP, /** * 方法级别限流 * key = ClassName+MethodName */ METHOD, /** * 参数级别限流 * key = ClassName+MethodName+Params */ PARAMS, /** * 用户级别限流 * key = ClassName+MethodName+Params+UserId */ USER, /** * 根据request的uri限流 * key = Request_uri */ REQUEST_URI, /** * 对requesturi+userId限流 * key = Request_uri+UserId */ REQUESTURI_USERID, /** * 对userId限流 * key = userId */ SINGLEUSER, /** * 对方法限流 * key = ClassName+MethodName */ SINGLEMETHOD, /** * 对uri+params限流 * key = uri+params */ REQUEST_URI_PARAMS, /** * 对uri+params+userId限流 * key = uri+params+userId */ REQUEST_URI_PARAMS_USERID; } 生成key的工具类

根据类型生成锁的对象(key)的工具类,使用map+函数式接口优化if,其中BaseContext是一个获取用户唯一标识userId的工具类

@Component public class ProceedingJoinPointUtil { @Autowired private HttpServletRequest request; private Map<LimitType, Function<ProceedingJoinPoint,String>> functionMap = new HashMap<>(9); @PostConstruct void initMap(){ //初始化策略 functionMap.put(LimitType.METHOD, this::getMethodTypeKey); functionMap.put(LimitType.PARAMS, this::getParamsTypeKey); functionMap.put(LimitType.USER, this::getUserTypeKey); functionMap.put(LimitType.REQUEST_URI,proceedingJoinPoint -> request.getRequestURI()); functionMap.put(LimitType.REQUESTURI_USERID, proceedingJoinPoint -> request.getRequestURI()+BaseContext.getUserId()); functionMap.put(LimitType.REQUEST_URI_PARAMS,proceedingJoinPoint -> request.getRequestURI()+getParams(proceedingJoinPoint)); functionMap.put(LimitType.REQUEST_URI_PARAMS_USERID,proceedingJoinPoint -> request.getRequestURI()+getParams(proceedingJoinPoint)+BaseContext.getUserId()); functionMap.put(LimitType.SINGLEUSER,(proceedingJoinPoint)-> String.valueOf(BaseContext.getUserId())); functionMap.put(LimitType.SINGLEMETHOD,(proceedingJoinPoint -> { StringBuilder sb = new StringBuilder(); appendMthodName(proceedingJoinPoint,sb); return sb.toString(); })); } public Object getKey(ProceedingJoinPoint joinPoint, RedisLimit redisLimit) { //根据限制类型生成key Object generateKey = ""; //自定义 if(redisLimit.type() != LimitType.CUSTOM){ generateKey = generateKey(redisLimit.type(), joinPoint); }else { //非自定义 generateKey = redisLimit.key(); } return generateKey; } /** * 根据LimitType生成key * @param type * @param joinPoint * @return */ private Object generateKey(LimitType type , ProceedingJoinPoint joinPoint) { Function function = functionMap.get(type); Object result = function.apply(joinPoint); return result; } /** * 方法级别 * key = ClassName+MethodName * @param joinPoint * @return */ private String getMethodTypeKey(ProceedingJoinPoint joinPoint){ StringBuilder sb = new StringBuilder(); appendMthodName(joinPoint, sb); return sb.toString(); } /** * 参数级别 * key = ClassName+MethodName+Params * @param joinPoint * @return */ private String getParamsTypeKey(ProceedingJoinPoint joinPoint){ StringBuilder sb = new StringBuilder(); appendMthodName(joinPoint, sb); appendParams(joinPoint, sb); return sb.toString(); } /** * 用户级别 * key = ClassName+MethodName+Params+UserId */ private String getUserTypeKey(ProceedingJoinPoint joinPoint){ StringBuilder sb = new StringBuilder(); appendMthodName(joinPoint, sb); appendParams(joinPoint, sb); //获取userId appendUserId(sb); return sb.toString(); } /** * StringBuilder添加类名和方法名 * @param joinPoint * @param sb */ private void appendMthodName(ProceedingJoinPoint joinPoint, StringBuilder sb) { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); sb.append(joinPoint.getTarget().getClass().getName())//类名 .append(method.getName());//方法名 } /** * StringBuilder添加方法参数值 * @param joinPoint * @param sb */ private void appendParams(ProceedingJoinPoint joinPoint, StringBuilder sb) { for (Object o : joinPoint.getArgs()) { sb.append(o.toString()); } } private String getParams(ProceedingJoinPoint joinPoint) { StringBuilder sb = new StringBuilder(); for (Object o : joinPoint.getArgs()) { if(o instanceof MultipartFile){ try { ImageTypeCheck.getImgHeightAndWidth(((MultipartFile) o).getInputStream()); } catch (IOException e) { throw new BusinessException("MultipartFile输入流获取失败,source:ProceedingJoinPointUtils.149",USER_PRINCIPAL_EMAIL); } }else { sb.append(o.toString()); } } return sb.toString(); } /** * StringBuilder添加UserId * @param sb */ private void appendUserId(StringBuilder sb) { sb.append(BaseContext.getUserId()); } } 定义aop具体逻辑 @Aspect @Component @Slf4j public class RedisLimitAspect { @Autowired private RedissonClient redissonClient; @Autowired private ProceedingJoinPointUtil proceedingJoinPointUtil; @Pointcut("@annotation(com.cat.www.aop.limit.anno.RedisLimit)") private void pointCut() { } @Around("pointCut() && @annotation(redisLimit)") private Object around(ProceedingJoinPoint joinPoint, RedisLimit redisLimit) { Object generateKey = proceedingJoinPointUtil.getKey(joinPoint, redisLimit); //redis key String key = redisLimit.prefix() +generateKey.toString(); //声明一个限流器 RRateLimiter rateLimiter = redissonClient.getRateLimiter(key); //设置速率,time秒中产生count个令牌 rateLimiter.trySetRate(RateType.OVERALL, redisLimit.count(), redisLimit.time(), RateIntervalUnit.SECONDS); // 试图获取一个令牌,获取到返回true boolean tryAcquire = rateLimiter.tryAcquire(); if (!tryAcquire) { return new ResultData<>().FAILED().setResultIns("访问过于频繁"); } Object obj = null; try { obj = joinPoint.proceed(); } catch (Throwable e) { throw new RuntimeException(); } return obj; } }

到此这篇关于Java Redisson多策略注解限流的文章就介绍到这了,更多相关Java Redisson内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!

推荐阅读

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    优化PostgreSQL中的批量更新性能

    优化PostgreSQL中的批量更新性能,数据,表格,在Ubuntu 12.04上使用PG 9.1. 我们目前需要24小时才能运行大量UPDATE数据库上的语句,其形式

    512内存的电脑优化|笔记本内存512

    512内存的电脑优化|笔记本内存512,,1. 笔记本内存512够用,因为运行非常流畅,苹果笔记本 16g512的运行内存是16g内存,机身内存是512g内存,运行

    Windows7下固态硬盘的优化技术

    Windows7下固态硬盘的优化技术,,当微软开发Windows Vista时,固态硬盘没有那么热,所以没有进行优化。Windows 7是不同的。微软从一开始就把SS

    记一次服务端系统性能优化

    记一次服务端系统性能优化,在线,设备, 首先简单介绍一下业务场景,物联网设备,关注公众号,免费领取环保袋。12月8号,也就是昨天上午,突然接

    幻灯片放映慢优化可以加快速度

    幻灯片放映慢优化可以加快速度,,用于制作幻灯片的一些技术更复杂,这些幻灯片在一些旧机器上运行缓慢或缓慢。在这种情况下,我们应该如何优化

    电脑cpu调整软件|电脑优化cpu的软件

    电脑cpu调整软件|电脑优化cpu的软件,,1. 电脑优化cpu的软件出现这个问题归根到底是因为你是用的模拟器,而模拟器是比较卡顿的,尤其在配置比

    bios优化设置|bios的优化设置

    bios优化设置|bios的优化设置,,1. bios的优化设置开机按del键,在bios设置菜单中选择loadfall-safe defaults,在弹出的确认提示中按y键即可

    hp超级本envy优化|hp envy bios

    hp超级本envy优化|hp envy bios,,hp超级本envy优化笔记本开机时显示报错码3f0表现为系统卡顿,原因和解决方法如下3、电脑同时开启了多个应