• Spring-aop +redssion 实现接口限流注解


    添加依赖环境

    1. <dependency>
    2. <groupId>org.redisson</groupId>
    3. <artifactId>redisson-spring-boot-starter</artifactId>
    4. <version>3.21.1</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>org.springframework.boot</groupId>
    8. <artifactId>spring-boot-starter-aop</artifactId>
    9. </dependency>
    10. .....

    yml 配置redis

    1. data:
    2. redis:
    3. host: 127.0.0.1
    4. port: 6379

    配置RedssionClient

    1. package com.chenkang.demo.config;
    2. import jakarta.annotation.Resource;
    3. import org.redisson.Redisson;
    4. import org.redisson.api.RedissonClient;
    5. import org.redisson.config.Config;
    6. import org.redisson.config.SingleServerConfig;
    7. import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
    8. import org.springframework.context.annotation.Bean;
    9. import org.springframework.context.annotation.Configuration;
    10. /**
    11. * @author chenkang
    12. * @since 2024/5/29 11:18
    13. */
    14. @Configuration
    15. public class RedisConfig {
    16. @Resource
    17. private RedisProperties redisProperties;
    18. @Bean
    19. public RedissonClient redisson() {
    20. Config config = new Config();
    21. SingleServerConfig singleServerConfig = config.useSingleServer();
    22. String address = "redis://" + redisProperties.getHost() + ":" + redisProperties.getPort();
    23. singleServerConfig.setAddress(address);
    24. return Redisson.create(config);
    25. }
    26. }

    spring 加入注解

    @EnableAspectJAutoProxy

    定义注解类型 以及切面

    1. package com.chenkang.demo.aop;
    2. /**
    3. * 接口限制类型
    4. * @author chenkang
    5. * @since 2024/5/29 21:09
    6. */
    7. public enum LimitType {
    8. /**
    9. * 请求者IP -- 通常是某个IP 不过会有人进行虚拟IP进行访问
    10. */
    11. IP,
    12. /**
    13. * 方法
    14. */
    15. METHOD,
    16. /**
    17. * 用户id
    18. */
    19. USER_ID;
    20. }
    1. package com.chenkang.demo.aop;
    2. import java.lang.annotation.*;
    3. /**
    4. * @author chenkang
    5. * @since 2024/5/29 21:07
    6. */
    7. @Target(value = {ElementType.METHOD})
    8. @Retention(value = RetentionPolicy.RUNTIME)
    9. public @interface RateLimiter {
    10. /**
    11. * 给定时间范围
    12. */
    13. int period() default 5;
    14. /**
    15. * 给定次数
    16. */
    17. int count() default 2;
    18. /**
    19. * 接口限流类型
    20. */
    21. LimitType limitType() default LimitType.METHOD;
    22. /**
    23. * 限流类型 限流的类型 1 超时等待 2 快速返回
    24. */
    25. int actor() default 2;
    26. /**
    27. *
    28. * 一超时时间秒,当actor=1是生效
    29. */
    30. int timeout() default 3;
    31. }
    1. package com.chenkang.demo.aop;
    2. import org.aopalliance.aop.Advice;
    3. import org.springframework.aop.Pointcut;
    4. import org.springframework.aop.support.AbstractPointcutAdvisor;
    5. import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
    6. import org.springframework.beans.BeansException;
    7. import org.springframework.beans.factory.BeanFactory;
    8. import org.springframework.beans.factory.BeanFactoryAware;
    9. import org.springframework.core.Ordered;
    10. /**
    11. * @author chenkang
    12. * @since 2024/5/29 21:04
    13. */
    14. public class RateLimiterAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware, Ordered {
    15. private Pointcut pointcut;
    16. private Advice advice;
    17. public RateLimiterAnnotationAdvisor(RateLimiterAnnotationInterceptor annotationInterceptor){
    18. this.pointcut=buildPointcut();
    19. this.advice=annotationInterceptor;
    20. }
    21. @Override
    22. public Pointcut getPointcut() {
    23. return pointcut;
    24. }
    25. @Override
    26. public Advice getAdvice() {
    27. return advice;
    28. }
    29. @Override
    30. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    31. if (this.advice instanceof BeanFactoryAware) {
    32. ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
    33. }
    34. }
    35. private Pointcut buildPointcut() {
    36. return AnnotationMatchingPointcut.forMethodAnnotation(RateLimiter.class);
    37. }
    38. @Override
    39. public int getOrder() {
    40. return 1;
    41. }
    42. }
    1. package com.chenkang.demo.aop;
    2. import com.chenkang.demo.util.IpUtils;
    3. import lombok.Setter;
    4. import org.aopalliance.intercept.MethodInterceptor;
    5. import org.aopalliance.intercept.MethodInvocation;
    6. import org.redisson.api.*;
    7. import org.springframework.aop.BeforeAdvice;
    8. import org.springframework.web.context.request.RequestContextHolder;
    9. import org.springframework.web.context.request.ServletRequestAttributes;
    10. import javax.annotation.Nonnull;
    11. import javax.annotation.Nullable;
    12. import java.lang.reflect.Method;
    13. import java.util.Optional;
    14. import java.util.concurrent.TimeUnit;
    15. /**
    16. * @author chenkang
    17. * @since 2024/5/29 21:14
    18. */
    19. @Setter
    20. public class RateLimiterAnnotationInterceptor implements MethodInterceptor, BeforeAdvice {
    21. private RedissonClient redissonClient;
    22. @Nullable
    23. @Override
    24. public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
    25. //代理执行的真正地方
    26. Method method = invocation.getMethod();
    27. RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class);
    28. String formatKey = formatKey(rateLimiter.limitType(), method);
    29. redissonRateLimiter(rateLimiter,formatKey);
    30. return invocation.proceed();
    31. }
    32. /**
    33. * 获取Redisson的RRateLimiter
    34. */
    35. private void redissonRateLimiter(RateLimiter limit, String key) {
    36. RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
    37. if (!rateLimiter.isExists()) {
    38. rateLimiter.trySetRate(RateType.OVERALL, limit.count(),limit.period(), RateIntervalUnit.SECONDS);
    39. }
    40. RateLimiterConfig rateLimiterConfig = rateLimiter.getConfig();
    41. Long rateInterval = rateLimiterConfig.getRateInterval();
    42. Long rate = rateLimiterConfig.getRate();
    43. if (TimeUnit.MILLISECONDS.convert(limit.period(), TimeUnit.SECONDS) != rateInterval || limit.count() != rate) {
    44. rateLimiter.delete();
    45. rateLimiter.setRate(RateType.OVERALL, limit.count(), limit.period(), RateIntervalUnit.SECONDS);
    46. }
    47. if (limit.actor() == 1) {
    48. rateLimiter.acquire();
    49. }
    50. if (limit.actor() == 2) {
    51. if(rateLimiter.tryAcquire(1,limit.timeout(),TimeUnit.SECONDS)) {return;}
    52. throw new RuntimeException("请求频繁,请稍后再试!");
    53. }
    54. }
    55. private String formatKey(LimitType limitType,Method method) {
    56. if (limitType.equals(LimitType.IP)) {
    57. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    58. return Optional.ofNullable(attributes).map(ServletRequestAttributes::getRequest).map(IpUtils::getRealClientIp).orElse("");
    59. }else if(limitType.equals(LimitType.METHOD)){
    60. return "limit:" + method.getClass().getSimpleName()+method.getName();
    61. }else {
    62. //TODO 获取当前登录人
    63. return "User";
    64. }
    65. }
    66. }
    1. package com.chenkang.demo.config;
    2. import com.chenkang.demo.aop.RateLimiterAnnotationAdvisor;
    3. import com.chenkang.demo.aop.RateLimiterAnnotationInterceptor;
    4. import org.redisson.api.RedissonClient;
    5. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    6. import org.springframework.context.annotation.Bean;
    7. import org.springframework.context.annotation.Configuration;
    8. /**
    9. * @author chenkang
    10. * @since 2024/5/29 21:21
    11. */
    12. @Configuration
    13. public class RateLimiterConfig {
    14. @Bean
    15. public RateLimiterAnnotationAdvisor lockAnnotationAdvisor(RateLimiterAnnotationInterceptor limiterAnnotationInterceptor) {
    16. return new RateLimiterAnnotationAdvisor(limiterAnnotationInterceptor);
    17. }
    18. @Bean
    19. public RateLimiterAnnotationInterceptor lockInterceptor(RedissonClient redisClient) {
    20. RateLimiterAnnotationInterceptor limiterAnnotationInterceptor = new RateLimiterAnnotationInterceptor();
    21. limiterAnnotationInterceptor.setRedissonClient(redisClient);
    22. return limiterAnnotationInterceptor;
    23. }
    24. }

    测试:

    @GetMapping("rateLimiter")
    @RateLimiter()
    public String  rateLimiter() {
        System.out.println(111);
        return "hhah";
    }

    全局异常捕获返回就可以了

  • 相关阅读:
    一、项目整合管理
    跟着官方文档学习axios
    vlan的学习笔记2(vlan间通信)
    gdb调试简要总结
    智慧工地综合管理平台-环境监测子系统集成部署方案
    环形链表的判断思路
    C++笔记 17 (STL常用容器 - stack & queue & list)
    微信自动化工具开发系列01_自动获取微信聊天信息(2022年7月可用)
    SQL Server 数据库之备份和恢复数据库
    css点击文字(非按钮) 能自动改变颜色。
  • 原文地址:https://blog.csdn.net/weixin_38845058/article/details/139308765