ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

简单限流器封装

2022-07-05 11:03:45  阅读:153  来源: 互联网

标签:return String value 60 限流 limit 简单 封装


简单限流器封装

开发过程中有时候 我们会做一些简单的限流 操作,比如 告警提醒,发送验证码 等,希望在 一段时间 只许调用几次。

下面基于redis incr 命令通用封装
@RequiredArgsConstructor
@Getter
public enum LimitTypeEnum {

	SECOND(1,"秒"),MINUTE(60,"分"),HOUR(60*60,"小时"),DAY(60*60*24,"天");
	/**
	 * 类型
	 */
	private final int time;

	/**
	 * 描述
	 */
	private final String description;
}

 * 限制调用次数
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {
	/**
	 * 限制次数
	 * @return
	 */
	long count() default 1L;

	/**
	 * 提示消息
	 * @return
	 */
	String msg() default "请求过于频繁";

	/**
	 * 是否带方法参数 md5(类名+方法名+方法参数)
	 * @return
	 */
	boolean param() default true;
	/**
	 * 限制类型
	 * @return
	 */
	LimitTypeEnum limitType() default LimitTypeEnum.SECOND;
}
@Aspect
@Component
public class LimitAspect {

	private static final String LOCK_REPEATED_SUBMIT = "limit:";

	@Autowired
	private RedisTemplate redisTemplate;

	@Around("@annotation(limit)")
	public Object around(ProceedingJoinPoint pjp, Limit limit) throws Throwable {
		try {
			//获取当前执行类
			String className = pjp.getSignature().getDeclaringTypeName();
			//获取当前执行类中的执行方法
			String methodName = pjp.getSignature().getName();
			String key = className + methodName;
			if(limit.param()){
				// 参数
				Map<String, Object> params = getRequestParams(pjp);
				key = key + JSON.toJSONString(params);
			}
			String md5 = SecureUtil.md5(key);
			String redisKey = LOCK_REPEATED_SUBMIT + md5;
			redisTemplate.opsForValue().setIfAbsent(redisKey, CommonConstants.ZERO,limit.limitType().getTime(),TimeUnit.SECONDS);
			Long count = redisTemplate.opsForValue().increment(redisKey);
			if(count <= limit.count()){
				Object result = pjp.proceed();
				return result;
			}
			throw new BusinessException(limit.msg());
		} catch (Throwable e) {
			throw e;
		}
	}


	/**
	 * 获取入参
	 * @param proceedingJoinPoint
	 *
	 * @return
	 * */
	private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
		Map<String, Object> requestParams = new HashMap<>();
		//参数名
		String[] paramNames =
				((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
		//参数值
		Object[] paramValues = proceedingJoinPoint.getArgs();

		for (int i = 0; i < paramNames.length; i++) {
			Object value = paramValues[i];
			//如果是文件对象
			if (value instanceof MultipartFile) {
				MultipartFile file = (MultipartFile) value;
				//获取文件名
				value = file.getOriginalFilename();
			}

			requestParams.put(paramNames[i], value);
		}

		return requestParams;
	}
}
使用

测试

可见并发测试的时候,有5 次请求 被拒绝了,限流成功。

限流还有其他 方式 令牌桶,漏桶,滑动窗口 等

有兴趣 参考 Guava, redisson https://github.com/redisson/redisson/wiki/6.-分布式对象#612-限流器ratelimiter (令牌桶)

标签:return,String,value,60,限流,limit,简单,封装
来源: https://www.cnblogs.com/lyc88/p/16445596.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有