1先自定义注解
@Target(value = ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ExtRateLimiter { double value(); long timeOut(); }
扫描二维码关注公众号,回复:
5755715 查看本文章
2 整合aop
1 /** 2 * 功能说明: 3 * 功能作者: 4 * 创建日期: 5 * 版权归属:每特教育|蚂蚁课堂所有 www.itmayiedu.com 6 */ 7 package com.itmayiedu.aop; 8 9 import java.io.IOException; 10 import java.io.PrintWriter; 11 import java.lang.reflect.Method; 12 import java.util.Map; 13 import java.util.concurrent.ConcurrentHashMap; 14 import java.util.concurrent.TimeUnit; 15 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletResponse; 18 19 import org.aspectj.lang.ProceedingJoinPoint; 20 import org.aspectj.lang.annotation.Around; 21 import org.aspectj.lang.annotation.Aspect; 22 import org.aspectj.lang.annotation.Pointcut; 23 import org.aspectj.lang.reflect.MethodSignature; 24 import org.springframework.stereotype.Component; 25 import org.springframework.web.context.request.RequestContextHolder; 26 import org.springframework.web.context.request.ServletRequestAttributes; 27 28 import com.google.common.util.concurrent.RateLimiter; 29 import com.itmayiedu.annotation.ExtRateLimiter; 30 31 /** 32 * 功能说明:使用AOP环绕通知判断拦截所有springmvc 请求,判断请求方法上是否存在ExtRateLimiter <br> 33 * 1.判断请求方法上是否有@ExtRateLimiter<br> 34 * 2.如果方法上存在@ExtRateLimiter注解话<br> 35 * 3.使用反射技术获取@ExtRateLimiter注解方法上的参数<br> 36 * 4.调用原生RateLimiter代码创建令牌桶<br> 37 * 5.如果获取令牌超时的,直接调用服务降级方法(需要自己定义)<br> 38 * 6.如果能够获取令牌的话,直接进入实际请求方法。<br> 39 * AOP创建方式有两种 注解版本和XML方式<br> 40 * <br> 41 * 创建作者:每特教育-余胜军<br> 42 */ 43 @Aspect 44 @Component 45 public class RateLimiterAop { 46 private Map<String, RateLimiter> rateHashMap = new ConcurrentHashMap<>(); 47 48 // 定义切入点 拦截com.itmayeidu.api 49 @Pointcut("execution(public * com.itmayeidu.api.*.*(..))") 50 51 public void rlAop() { 52 } 53 54 // 使用AOP环绕通知判断拦截所有springmvc 请求,判断请求方法上是否存在ExtRateLimiter注解 55 @Around("rlAop()") 56 public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 57 // 1.如果请求方法上存在@ExtRateLimiter注解的话 58 Method sinatureMethod = getSinatureMethod(proceedingJoinPoint); 59 if (sinatureMethod == null) { 60 // 直接报错 61 return null; 62 } 63 // 2.使用java的反射机制获取拦截方法上自定义注解的参数 64 ExtRateLimiter extRateLimiter = sinatureMethod.getDeclaredAnnotation(ExtRateLimiter.class); 65 if (extRateLimiter == null) { 66 // 直接进入实际请求方法中 67 return proceedingJoinPoint.proceed(); 68 } 69 double permitsPerSecond = extRateLimiter.permitsPerSecond(); 70 long timeout = extRateLimiter.timeout(); 71 // 3.调用原生的RateLimiter创建令牌 保证每个请求对应都是单例的RateLimiter 72 // /index---RateLimiter /order --RateLimiter 使用hashMap key为 请求的url地址## 73 // 相同的请求在同一个桶 74 String requestURI = getRequestURI(); 75 RateLimiter rateLimiter = null; 76 if (rateHashMap.containsKey(requestURI)) { 77 // 如果在hashMap URL 能检测到RateLimiter 78 rateLimiter = rateHashMap.get(requestURI); 79 } else { 80 // 如果在hashMap URL 没有检测到RateLimiter 添加新的RateLimiter 81 rateLimiter = RateLimiter.create(permitsPerSecond); 82 rateHashMap.put(requestURI, rateLimiter); 83 } 84 // 4.获取令牌桶中的令牌,如果没有有效期获取到令牌的话,则直接调用本地服务降级方法,不会进入到实际请求方法中。 85 boolean tryAcquire = rateLimiter.tryAcquire(timeout, TimeUnit.MILLISECONDS); 86 if (!tryAcquire) { 87 // 服务降级 88 fallback(); 89 return null; 90 } 91 // 5.获取令牌桶中的令牌,如果能在有效期获取令牌到令的话,则直接进入到实际请求方法中。 92 // 直接进入实际请求方法中 93 return proceedingJoinPoint.proceed(); 94 } 95 96 private void fallback() throws IOException { 97 System.out.println("服务降级别抢了, 在抢也是一直等待的, 还是放弃吧!!!"); 98 // 在AOP编程中获取响应 99 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 100 HttpServletResponse response = attributes.getResponse(); 101 response.setHeader("Content-type", "text/html;charset=UTF-8"); 102 PrintWriter writer = response.getWriter(); 103 try { 104 writer.println("别抢了, 在抢也是一直等待的, 还是放弃吧!!!"); 105 } catch (Exception e) { 106 107 } finally { 108 writer.close(); 109 110 } 111 112 } 113 114 private String getRequestURI() { 115 return getRequest().getRequestURI(); 116 } 117 118 private HttpServletRequest getRequest() { 119 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 120 return attributes.getRequest(); 121 } 122 123 // 获取到AOP拦截的方法 124 private Method getSinatureMethod(ProceedingJoinPoint proceedingJoinPoint) { 125 MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature(); 126 // 获取到AOP拦截的方法 127 Method method = signature.getMethod(); 128 return method; 129 } 130 131 }