利用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


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