整体思路:

一 具体接口,可以自定义一个注解,配置限流量,然后对需要限流的方法加上注解即可!

二 容器初始化的时候扫描所有所有controller,并找出需要限流的接口方法,获取对应的限流量

三 使用拦截器或者aop,对加上注解的方法进行限流,采用配置的信号量

自定义注解

  1. /**
  2. * 限流注解
  3. */
  4. @Target(ElementType.METHOD) //作用与方法上
  5. @Retention(RetentionPolicy.RUNTIME) //注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
  6. @Documented
  7. public @interface ApiRateLimit {
  8. int value(); //控制并发最大数量
  9. }

  

出初始化限流配置,注意:这里设置的如果限流量一样,则两个方法一起限流,比如两个方法限流量都是5,则两个方法总共可以支持最多5个线程访问

实际可以自己调整,加个方法名当key,则可以保证每个方法都独自限流:

  1. /**
  2. * ApplicationContextAware实现类可以获得spring上下文
  3. * 间接获取ApplicationContext中的所有bean,向切面添加所有接口的配置的限流量
  4. */
  5. @Component
  6. public class InitApiLimit implements ApplicationContextAware {
  7. @Override
  8. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  9. Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(RestController.class);
  10. System.out.println(beanMap.size());
  11. beanMap.forEach((k,v)->{
  12. Class<?> controllerClass = v.getClass();
  13. System.out.println(controllerClass.toString());
  14. System.out.println(controllerClass.getSuperclass().toString());
  15. //获取所有声明的方法
  16. Method[] allMethods = controllerClass.getSuperclass().getDeclaredMethods();
  17. for (Method method:allMethods){
  18. System.out.println(method.getName());
  19. //判断方法是否使用了限流注解
  20. if (method.isAnnotationPresent(ApiRateLimit.class)){
  21. //获取配置的限流量,实际值可以动态获取,配置key,根据key从配置文件获取
  22. int value = method.getAnnotation(ApiRateLimit.class).value();
  23. String key = String.valueOf(value);
  24. //key作为key.value为具体限流量,传递到切面的map中
  25. ApiLimitAspect.semaphoreMap.put(key,new Semaphore(value));
  26. }
  27. }
  28. System.out.println("----信号量个数:"+ApiLimitAspect.semaphoreMap.size());
  29. });
  30. }
  31. }

  注意:这里有一点需要说明,一旦使用了代理,因为是controller',没有借口,所以是cglib,会创建子类

,此时从容器中获取的是代理的子类,默认是不会有自定义注解的,所以得getSuperClass,从父类,即controller中获取注解信息

编写切面,这里是最主要的,使用jdk自带的信号量:

限流切面

  1. /**
  2. * 限流切面
  3. */
  4. @Aspect
  5. @Order(value = Ordered.HIGHEST_PRECEDENCE) //最高优先级
  6. @Component
  7. public class ApiLimitAspect {
  8. //存储限流量和方法,必须是static且线程安全,保证所有线程进入都唯一
  9. public static Map<String, Semaphore> semaphoreMap= new ConcurrentHashMap<>();
  10. //拦截所有controller 的所有方法
  11. @Around("execution(* com.hou.serviceorder.controller.*.*(..))")
  12. public Object around(ProceedingJoinPoint joinPoint){
  13. Object result=null;
  14. Semaphore semaphore=null;
  15. Class<?> clz = joinPoint.getTarget().getClass();//获取目标对象
  16. Signature signature = joinPoint.getSignature();//获取增强方法信息
  17. String name = signature.getName();
  18. String limitKey = String.valueOf(getLimitKey(clz, name));
  19. if(limitKey!=null && !"".equals(limitKey)){
  20. semaphore = semaphoreMap.get(limitKey);
  21. try {
  22. semaphore.acquire();
  23. result=joinPoint.proceed();
  24. } catch (Throwable e) {
  25. e.printStackTrace();
  26. } finally {
  27. semaphore.release();
  28. }
  29. }
  30. return result;
  31. }
  32.  
  33. //获取拦截方法配置的限流key,没有返回null
  34. private Integer getLimitKey(Class<?> clz, String methodName){
  35. for (Method method:clz.getDeclaredMethods()){
  36. if(method.getName().equals(methodName)){//找出目标方法
  37. if(method.isAnnotationPresent(ApiRateLimit.class)){//判断是否是限流方法
  38. return method.getAnnotation(ApiRateLimit.class).value();
  39. }
  40. }
  41. }
  42. return null;
  43. }
  44. }

  

使用注解

  1. @ApiRateLimit(value = 5)
  2. @GetMapping("/name")
  3. public String getOrderName() throws InterruptedException {
  4. System.out.println("-----进入getOrder方法------");
  5. TimeUnit.SECONDS.sleep(2);
  6. return "order";
  7. }
  8.  
  9. @ApiRateLimit(value = 5)
  10. @GetMapping("/order")
  11. public Order getOrder(String id) throws InterruptedException {
  12. System.out.println("-----进入getOrder方法------");
  13. TimeUnit.SECONDS.sleep(2);
  14. return new Order(id,"侯征");
  15. }

  

测试

  1. public class TestSe {
  2.  
  3. public static void main(String[] args) {
  4. //测试信号并发量
  5. for (int i = 0; i < 10; i++) {
  6. new Thread(()->{
  7. //访问目标接口
  8. RestTemplate restTemplate = new RestTemplate();
  9. restTemplate.getForObject("http://localhost:8081/order/name",String.class);
  10. }).start();
  11. }
  12. }
  13. }

  会发现最多5个一起打印:

使用AOP和Semaphore对项目中具体的某一个接口进行限流的更多相关文章

  1. 转:C4项目中验证用户登录一个特性就搞定

    转:C4项目中验证用户登录一个特性就搞定   在开发过程中,需要用户登陆才能访问指定的页面这种功能,微软已经提供了这个特性.     // 摘要:    //     表示一个特性,该特性用于限制调用 ...

  2. java web项目(spring项目)中集成webservice ,实现对外开放接口

    什么是WebService?webService小示例 点此了解 下面进入正题: Javaweb项目(spring项目)中集成webservice ,实现对外开放接口步骤: 准备: 采用与spring ...

  3. 一个项目中:只能存在一个 WebMvcConfigurationSupport (静态文件失效之坑)

    一个项目中:只能存在一个 WebMvcConfigurationSupport 在一个项目中WebMvcConfigurationSupport只能存在一个,多个的时候,只有一个会生效. 静态文件访问 ...

  4. 《 .NET并发编程实战》一书中的节流为什么不翻译成限流

    有读者问,为什么< .NET并发编程实战>一书中的节流为什么不翻译成限流? 这个问题问得十分好!毕竟“限流”这个词名气很大,耳熟能详,知名度比“节流”大多了. 首先,节流的原词Thrott ...

  5. Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Ocelot+Polly缓存、限流、熔断、降级

    相关文章 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网 ...

  6. iOS中AOP与Method Swizzling 项目中的应用

    引子:项目中需要对按钮点击事件进行统计分析,现在项目中就是在按钮的响应代码中添加点击事件,非常繁琐.所以使用了AOP(面向切面编程),将统计的业务逻辑统一抽离出来. 项目中添加的开源库:https:/ ...

  7. C#.NET常见问题(FAQ)-程序如何把窗体文件从从一个项目中复制到另一个项目

    一个窗体有三个文件,全部拷贝到新的项目中   在新的项目中点击显示所有文件,然后右击导入的文件,点击包括在项目中,会自动修改颜色(此时还没有被识别为窗体)   重启这个项目,三个文件已经被识别出来了 ...

  8. C#程序如何把窗体文件从从一个项目中复制到另一个项目

    一个窗体有三个文件,全部拷贝到新的项目中   在新的项目中点击显示所有文件,然后右击导入的文件,点击包括在项目中,会自动修改颜色(此时还没有被识别为窗体)   重启这个项目,三个文件已经被识别出来了 ...

  9. 在.net core web api项目中安装swagger展示api接口(相当于生成api文档)

    1,  建立或打开项目后,在“程序包管理器控制台”中执行以下命令添加包引用: Install-Package Swashbuckle.AspNetCore 2,在项目中打开Startup.cs文件,找 ...

随机推荐

  1. SpringJDBC的使用(转载)

    转载自   https://www.yiibai.com/spring/maven-spring-jdbc-example.html 工具: eclipse4.7.2及mysql-8.0.13 项目最 ...

  2. 用c++ 给易语言写支持库学习记录

    废话我就不对说 直接开始 易语言官方下载的易语言安装路径下 有一个SDK文件夹 我们点进入cpp文件夹里面提供是c++的SDK elib文件夹里就是sdk 我们新建一个win32项目 这里我用的是VS ...

  3. 【题解】HDU4689 Derangement(有技巧的计数DP)

    [题解]HDU4689 Derangement(有技巧的计数DP) 传送门 呵呵没告诉我多测组数,然后\(n\le 20,7000\mathrm{ms}\)我写了个状压上去T了 题目大意: 要你求错排 ...

  4. IDEA到期了?不用怕,最新的永久激活送给你

    今天发现好多人的IDEA激活码都到期了,IDEA社区版又不能满足开发需求,因此写这篇IDEA的激活文章,希望对大家有用. 以下方法的破解文件的是永久破解的,不存在过期时间. 当然,有条件还是买正版授权 ...

  5. 7.netty内存管理-ByteBuf

    ByteBuf ByteBuf是什么 ByteBuf重要API read.write.set.skipBytes mark和reset duplicate.slice.copy retain.rele ...

  6. DispatcherServlet的url-pattern尽量不要配置为"/*"

    DispatcherServlet的url-pattern尽量不要配置为"/*" 原因 当Dispatcher的url配置为"/*"时,会把tomcat的web ...

  7. Django 多表、跨表、聚合、分组查询

    前期准备: 创建表 class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalFi ...

  8. 从N个元素中抽取K个不重复元素(抽奖问题)

    核心就是 把N数组抽中的元素给K数组 把N数组最后一位给N数组被抽走的那一位(这时候N数组最后一位元素和被抽走的那位元素值相等) 把N数组长度减一,去除最后一位

  9. linux常用命令,最基础

    rmdir keda1/ 6 touch test.java 创建空文件 7 拷贝文件 cp 源文件 目标文件 cp test.java test1.java 8 删除文件rm -r 递归删除 -rf ...

  10. ArcGIS Enterprise 10.6 (Windows)安装及部署图解

    目录 前言 1 本地环境配置 1.1 机器名修改 1.2 安装和配置IIS 2 ArcGIS for Server 2.1 安装 ArcGIS for Server 2.2 配置 ArcGIS for ...