互联网并发与安全系列教程(03) - RateLimiter使用AOP方式实现限流

简介: 互联网并发与安全系列教程(03) - RateLimiter使用AOP方式实现限流

在上一节,我们学习了限流的方案:

  • 限流算法(如:令牌桶、漏桶、计数器)
  • 应用层解决
  • 接入层解决(如Nginx)

我们知道RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流,并且根据系统的实际情况来调整生成token的速率。本文通过仿写RateLimiter来实现限流,下面直接实现代码(讲解主要的代码):

1.Controller层:

@RequestMapping("/myOrder")
@ExtRateLimiter(value = 10.0, timeOut = 500)
public String myOrder() throws InterruptedException {
    System.out.println("myOrder");
    return "SUCCESS";
}

2.自定义注解:

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtRateLimiter {
  double value();
  long timeOut();
}

3.AOP切面类:由于每个方法都基本会用到,所以写成切面类,避免代码的重复编写

@Aspect
@Component
public class RateLimiterAop {
  // 存放接口是否已经存在
  private static ConcurrentHashMap<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<String, RateLimiter>();
  @Pointcut("execution(public * com.xxx.api.*.*(..))")
  public void rlAop() {
  }
  @Around("rlAop()")
  public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
    // 使用Java反射技术获取方法上是否有@ExtRateLimiter注解类
    ExtRateLimiter extRateLimiter = signature.getMethod().getDeclaredAnnotation(ExtRateLimiter.class);
    if (extRateLimiter == null) {
      // 正常执行方法
      Object proceed = proceedingJoinPoint.proceed();
      return proceed;
    }
    // ############获取注解上的参数 配置固定速率 ###############
    // 获取配置的速率
    double value = extRateLimiter.value();
    // 获取等待令牌等待时间
    long timeOut = extRateLimiter.timeOut();
    RateLimiter rateLimiter = getRateLimiter(value, timeOut);
    // 判断令牌桶获取token 是否超时
    boolean tryAcquire = rateLimiter.tryAcquire(timeOut, TimeUnit.MILLISECONDS);
    if (!tryAcquire) {
      serviceDowng();
      return null;
    }
    // 获取到令牌,直接执行..
    Object proceed = proceedingJoinPoint.proceed();
    return proceed;
  }
  // 获取RateLimiter对象
  private RateLimiter getRateLimiter(double value, long timeOut) {
    // 获取当前URL
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    String requestURI = request.getRequestURI();
    RateLimiter rateLimiter = null;
    if (!rateLimiterMap.containsKey(requestURI)) {
      // 开启令牌通限流
      rateLimiter = RateLimiter.create(value); // 独立线程
      rateLimiterMap.put(requestURI, rateLimiter);
    } else {
      rateLimiter = rateLimiterMap.get(requestURI);
    }
    return rateLimiter;
  }
  // 服务降级
  private void serviceDowng() throws IOException {
    // 执行服务降级处理
    System.out.println("执行降级方法,服务器忙!请稍后重试!");
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletResponse response = attributes.getResponse();
    response.setHeader("Content-type", "text/html;charset=UTF-8");
    PrintWriter writer = response.getWriter();
    try {
      writer.println("执行降级方法,服务器忙!请稍后重试!");
    } catch (Exception e) {
    } finally {
      writer.close();
    }
  }
}


目录
相关文章
|
7月前
|
监控 Java API
掌握 Spring Boot AOP:使用教程
Spring Boot 中的面向切面编程(AOP)为软件开发提供了一种创新方法,允许开发者将横切关注点与业务逻辑相分离。这不仅提高了代码的复用性和可维护性,而且还降低了程序内部组件之间的耦合度。下面,我们深入探讨如何在 Spring Boot 应用程序中实践 AOP,以及它为项目带来的种种益处。
|
7月前
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
5月前
|
分布式计算 Java MaxCompute
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
详解 Java 限流接口实现问题之在Spring框架中使用AOP来实现基于注解的限流问题如何解决
|
设计模式 安全 Java
源码分析系列教程(01) - Spring核心总结(AOP篇)
源码分析系列教程(01) - Spring核心总结(AOP篇)
44 0
|
Java 程序员 数据安全/隐私保护
Spring AOP -- Spring快速入门保姆级教程(三)(2)
Spring AOP -- Spring快速入门保姆级教程(三)
101 0
|
Java Spring 容器
Spring AOP -- Spring快速入门保姆级教程(三)(1)
Spring AOP -- Spring快速入门保姆级教程(三)
101 0
|
消息中间件 NoSQL 应用服务中间件
使用Aop+Redis+lua限流,优化高并发问题
应用层也是需要做限流操作的。这里简单结合Aop+redis+lua来实现。注:如果是需要接入层先流的话,建议还是要使用nginx自带的连接数限流模块和请求限流模块。
232 0
使用Aop+Redis+lua限流,优化高并发问题
|
XML SQL 安全
Spring6详细教程(六)---&gt;面向切面编程AOP
从 0 开始学 Java 知识之 Java-学习路线 中的《Spring6---&gt;面向切面编程AOP》,不定期更新所学笔记
258 0
|
缓存 NoSQL 算法
springboot + aop + Lua分布式限流的最佳实践
分布式限流的几种实现方式
1432 0
|
3月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
73 1