• spirngboot项目 使用AOP限流用户单位时间请求接口次数


    说明:使用AOP+redis 实现限制用户单位时间内多次访问接口,我这里使用参数中的userId(用户唯一标识),也可以通过IP或者其他参数来做限制。

    1. package com.student.demo.configuration;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.context.annotation.Configuration;
    4. import org.springframework.data.redis.cache.RedisCacheConfiguration;
    5. import org.springframework.data.redis.cache.RedisCacheManager;
    6. import org.springframework.data.redis.connection.RedisConnectionFactory;
    7. import org.springframework.data.redis.core.RedisTemplate;
    8. import org.springframework.data.redis.serializer.*;
    9. import java.time.Duration;
    10. /**
    11. * @Date: 2023/2/9
    12. */
    13. @Configuration
    14. public class RedisConfig {
    15. @Bean
    16. public RedisTemplate redisTemplate(RedisConnectionFactory factory){
    17. RedisSerializer redisSerializer = new StringRedisSerializer();
    18. //Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    19. JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
    20. GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    21. //ObjectMapper om = new ObjectMapper();
    22. 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括privatepublic
    23. //om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    24. 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
    25. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    26. //om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.EVERYTHING, JsonTypeInfo.As.PROPERTY);
    27. //jackson2JsonRedisSerializer.setObjectMapper(om);
    28. RedisTemplate template = new RedisTemplate<>();
    29. template.setConnectionFactory(factory);
    30. template.setKeySerializer(redisSerializer);
    31. template.setValueSerializer(genericJackson2JsonRedisSerializer);
    32. template.setHashKeySerializer(redisSerializer);
    33. template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
    34. template.afterPropertiesSet();
    35. return template;
    36. }
    37. }

    自定义注解

    1. package com.student.demo.annotation;
    2. import java.lang.annotation.*;
    3. /**
    4. * @Date: 2023/9/7
    5. */
    6. @Documented
    7. @Target(ElementType.METHOD)
    8. @Retention(RetentionPolicy.RUNTIME)
    9. public @interface AccessLimit {
    10. /**
    11. * 限制时间 单位:秒(默认值:1分钟)
    12. * @return
    13. */
    14. long period() default 60;
    15. /**
    16. * 允许请求的次数(默认值:5次)
    17. * @return
    18. */
    19. long count() default 5;
    20. }

    AOP部分

    1. package com.student.demo.aop;
    2. import com.alibaba.fastjson.JSON;
    3. import com.alibaba.fastjson.JSONObject;
    4. import com.student.demo.annotation.AccessLimit;
    5. import com.student.demo.enums.RetCode;
    6. import com.student.demo.exception.BizException;
    7. import lombok.extern.slf4j.Slf4j;
    8. import org.aspectj.lang.ProceedingJoinPoint;
    9. import org.aspectj.lang.annotation.Around;
    10. import org.aspectj.lang.annotation.Aspect;
    11. import org.aspectj.lang.annotation.Pointcut;
    12. import org.aspectj.lang.reflect.MethodSignature;
    13. import org.springframework.core.annotation.AnnotationUtils;
    14. import org.springframework.data.redis.core.RedisTemplate;
    15. import org.springframework.data.redis.core.ZSetOperations;
    16. import org.springframework.stereotype.Component;
    17. import javax.annotation.Resource;
    18. import java.lang.reflect.Method;
    19. import java.util.concurrent.TimeUnit;
    20. /**
    21. * @Date: 2023/9/7
    22. */
    23. @Slf4j
    24. @Aspect
    25. @Component
    26. public class AccessLimitAspect {
    27. @Resource
    28. private RedisTemplate redisTemplate;
    29. @Pointcut("@annotation(com.student.demo.annotation.AccessLimit)")
    30. public void methodPointcut(){}
    31. @Around(value = "methodPointcut()")
    32. public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    33. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    34. Method method = signature.getMethod();
    35. AccessLimit annotation = AnnotationUtils.findAnnotation(method, AccessLimit.class);
    36. // get parameter from annotation
    37. long period = annotation.period();
    38. long limitCount = annotation.count();
    39. // get request info from args
    40. Object[] args = joinPoint.getArgs();
    41. JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(args[0]));
    42. String userId = jsonObject.getString("userId");
    43. String key = "ACCESS_LIMIT:".concat(userId);
    44. ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    45. // add current timestamp
    46. long currentMs = System.currentTimeMillis();
    47. zSetOperations.add(key, currentMs, currentMs);
    48. // set the expiration time for the code user
    49. redisTemplate.expire(key, period, TimeUnit.SECONDS);
    50. // remove the value that out of current window
    51. zSetOperations.removeRangeByScore(key, 0, currentMs - period * 1000);
    52. // check all available count
    53. Long count = zSetOperations.zCard(key);
    54. if (count > limitCount) {
    55. log.error("接口拦截:{} 请求超过限制频率【{}次/{}s】,UserId为:{}", method.getName(), limitCount, period, userId);
    56. }
    57. // execute the user request
    58. return joinPoint.proceed();
    59. }
    60. }

  • 相关阅读:
    【汇编语言03】第2章 寄存器——实验1:查看CPU和内存,用机器指令和汇编指令编程
    大模型重塑软件开发,华为云AI原生应用架构设计与实践分享
    【Redis】Redis安装步骤和特性以及支持的10种数据类型(Redis专栏启动)
    深入了解百度爬虫工作原理
    硬核!最全Java面试宝典+Java核心知识集一箭双雕杠秋招
    三分钟带你JAVA入门,1000多个人看了都说好
    Arduino驱动ICG-20660L传感器(惯性测量传感器篇)
    第20章 使用Spring进行事务管理(三)
    Linux学习-49-列出进程调用或打开的文件信息(lsof命令)
    手写RPC框架--4.服务注册
  • 原文地址:https://blog.csdn.net/aayygg1234/article/details/132765056