使用方式 查看结果(这里使用了自定义异常) 使用 AOP + redis 实现 使用方式为什么要接口限流
为什么要做分布式
我们要考虑模块,节点间的共享实现方式
1. 算法实现(无分布式,单体架构,单节点)
package com.yxl.annotation; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; /** * <p> * 限流注解, * </p> */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RateLimiter { int NOT_LIMITED = 0; /** * qps */ @AliasFor("qps") double value() default NOT_LIMITED; /** * qps */ @AliasFor("value") double qps() default NOT_LIMITED; /** * 超时时长 */ int timeout() default 0; /** * 超时时间单位 */ TimeUnit timeUnit() default TimeUnit.MILLISECONDS; }
package com.yxl.aspect; import com.yxl.annotation.RateLimiter; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * <p> * 限流切面 * </p> * * @author yxl * @date Created in 2019/9/12 14:27 */ @Slf4j @Aspect @Component public class RateLimiterAspect { private static final ConcurrentMap<String, com.google.common.util.concurrent.RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>(); @Pointcut("@annotation(com.yxl.annotation.RateLimiter)") public void rateLimit() { } @Around("rateLimit()") public Object pointcut(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解 RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class); if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) { double qps = rateLimiter.qps(); if (RATE_LIMITER_CACHE.get(method.getName()) == null) { // 初始化 QPS RATE_LIMITER_CACHE.put(method.getName(), com.google.common.util.concurrent.RateLimiter.create(qps)); } log.debug("【{}】的QPS设置为: {}", method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate()); // 尝试获取令牌 if (RATE_LIMITER_CACHE.get(method.getName()) != null && !RATE_LIMITER_CACHE.get(method.getName()).tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) { throw new RuntimeException("手速太快了,慢点儿吧~"); } } return point.proceed(); } }
2. 分布式实现
package com.yxzapp.annotation; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; import java.util.concurrent.TimeUnit; /** * <p> * 限流注解, * </p> */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RateLimiter { int NOT_LIMITED = 0; /** * 类名 * @return */ String className() default ""; /** * qps */ @AliasFor("qps") double value() default NOT_LIMITED; /** * qps */ @AliasFor("value") double qps() default NOT_LIMITED; /** * 限流时间 */ int timeout() default 0; /** * 超时时间单位 */ TimeUnit timeUnit() default TimeUnit.MILLISECONDS; }
package com.yxzapp.aspect; import com.yxzapp.annotation.RateLimiter; import com.yxzapp.commons.constant.MessageConstant; import com.yxzapp.exception.BizException; import com.yxzapp.modules.sys.entity.SysUser; import com.yxzapp.utils.RedisUtils; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * <p> * 限流切面 * </p> * * @author yxl * @date 2020/6/19 */ @Slf4j @Aspect @Component public class RateLimiterAspect { @Autowired private RedisUtils redisUtils; @Pointcut("@annotation(com.yxzapp.annotation.RateLimiter)") public void rateLimit() { } @Around("rateLimit()") public Object pointcut(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); Class aClass = signature.getClass(); // 获取方法上的@RateLimiter注解 RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class); if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) { //获取qps double qps = rateLimiter.qps(); // ip 加方法名 String key = "RateLimiter:" rateLimiter.className() + +':'+ method.getName(); if(!redisUtils.hasKey(key)){ redisUtils.setMillisecond(key,rateLimiter.qps(),rateLimiter.timeout()); }else if(redisUtils.get(key) != null) { throw new BizException(MessageConstant.MSG_STATUS,"手速太快了,慢点儿吧~"); } log.debug("【{}】的QPS设置为: {}", key, redisUtils.get(key)); } return point.proceed(); } }
查看结果 (这里使用了自定义异常)
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算