利用spring如何实现接口限流

  利用spring如何实现接口限流

  1.创建自定义注解

  **

  * 限流注解

  */

  @Inherited

  @Documented

  @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})

  @Retention(RetentionPolicy.RUNTIME)

  public @interface AccessLimit {

  //限流唯一标识

  String key() default "";

  //限流时间

  int time();

  //限流次数

  int count();

  }

  创建限流配置类

  /**

  * 注解拦截

  */

  @Slf4j

  @Aspect

  @Configuration

  public class AccessLimitConfig {

  @Autowired

  private RedisTemplate redisTemplate;

  @Autowired

  private DefaultRedisScript redisScript;

  /**

  * 执行redis的具体方法,限制method,保证没有其他的东西进来

  *

  * @return

  */

  @Around("execution(* com.mayday.auth.controller ..*(..) )")

  public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {

  MethodSignature signature = (MethodSignature) joinPoint.getSignature();

  Method method = signature.getMethod();

  Class targetClass = method.getDeclaringClass();

  AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);

  if (accessLimit != null) {

  //获取request对象

  HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

  String ipAddr = IpUtils.getIpAddr(request);

  String string = ipAddr + "-" + targetClass.getName() + "- " + method.getName() + "-" + accessLimit.key();

  List keys = Collections.singletonList(string);

  Number number = redisTemplate.execute(redisScript, keys, accessLimit.count(), accessLimit.time());

  if (number != null && number.intValue() != 0 && number.intValue() <= accessLimit.count()) {

  return joinPoint.proceed();

  }

  } else {

  return joinPoint.proceed();

  }

  return new Result(false, StatusCode.REPEAT_OPERATE);

  }

  }

  3. 创建切面类

  /**

  * 限流配置

  */

  @Slf4j @Component

  public class AccessLimitAspect {

  /**

  * 读取限流脚本

  *

  * @return

  */

  @Bean

  public DefaultRedisScript redisLuaScript() {

  DefaultRedisScript redisScript = new DefaultRedisScript<>();

  redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redisLimit.lua")));

  //返回类型郑州哪个妇科医院好 http://www.sptdfk.com/

  redisScript.setResultType(Number.class);

  return redisScript;

  }

  /**

  * RedisTemplate

  *

  * @return

  */

  @Bean

  public RedisTemplate limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {

  RedisTemplate template = new RedisTemplate<>();

  template.setKeySerializer(new StringRedisSerializer());

  template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

  template.setConnectionFactory(redisConnectionFactory);

  return template;

  }

  }

  Lua脚本

  --Lua脚本

  --IP限流Lua脚本

  --- 限流KEY资源唯一标识

  local key = "rate.limit:" .. KEYS[1]

  --- 时间窗最大并发数

  local limit = tonumber(ARGV[1])

  --- -过期时间

  local expire_time = ARGV[2]

  local is_exists = redis.call("EXISTS", key)

  if is_exists == 1 then

  if redis.call("INCR", key) > limit then

  return 0

  else

  return 1

  end

  else

  redis.call("SET", key, 1)

  redis.call("EXPIRE", key, expire_time)

  return 1

  end


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章