package org.sc.goods.manage.aop; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.sc.goods.manage.annotation.ExtRateLimiter; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.google.common.util.concurrent.RateLimiter; /** * @date: 2019年5月8日 下午3:03:28 */ @Aspect @Component public class RateLimiterAop { private Map<String, RateLimiter> rateHashMap = new ConcurrentHashMap<>(); // 定义切入点 拦截 @Pointcut("execution(* org.sc.goods.manage.controller..*.*(..))") public void rlAop() { } // 使用AOP环绕通知判断拦截所有springmvc 请求,判断请求方法上是否存在ExtRateLimiter注解 @Around("rlAop()") public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 1.如果请求方法上存在@ExtRateLimiter注解的话 Method sinatureMethod = getSinatureMethod(proceedingJoinPoint); if (sinatureMethod == null) { // 直接报错 return null; } // 2.使用java的反射机制获取拦截方法上自定义注解的参数 ExtRateLimiter extRateLimiter = sinatureMethod.getDeclaredAnnotation(ExtRateLimiter.class); if (extRateLimiter == null) { // 直接进入实际请求方法中 return proceedingJoinPoint.proceed(); } double permitsPerSecond = extRateLimiter.permitsPerSecond(); long timeout = extRateLimiter.timeout(); // 3.调用原生的RateLimiter创建令牌 保证每个请求对应都是单例的RateLimiter // /index---RateLimiter /order --RateLimiter 使用hashMap key为 请求的url地址## // 相同的请求在同一个桶 String requestURI = getRequestURI(); RateLimiter rateLimiter = null; if (rateHashMap.containsKey(requestURI)) { // 如果在hashMap URL 能检测到RateLimiter rateLimiter = rateHashMap.get(requestURI); } else { // 如果在hashMap URL 没有检测到RateLimiter 添加新的RateLimiter rateLimiter = RateLimiter.create(permitsPerSecond); rateHashMap.put(requestURI, rateLimiter); } // 4.获取令牌桶中的令牌,如果没有有效期获取到令牌的话,则直接调用本地服务降级方法,不会进入到实际请求方法中。 boolean tryAcquire = rateLimiter.tryAcquire(timeout, TimeUnit.MILLISECONDS); if (!tryAcquire) { // 服务降级 fallback(); return null; } // 5.获取令牌桶中的令牌,如果能在有效期获取令牌到令的话,则直接进入到实际请求方法中。 // 直接进入实际请求方法中 return proceedingJoinPoint.proceed(); } private void fallback() throws IOException { System.out.println("服务降级!!!"); // 在AOP编程中获取响应 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(); } } private String getRequestURI() { return getRequest().getRequestURI(); } private HttpServletRequest getRequest() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return attributes.getRequest(); } // 获取到AOP拦截的方法 private Method getSinatureMethod(ProceedingJoinPoint proceedingJoinPoint) { MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature(); // 获取到AOP拦截的方法 Method method = signature.getMethod(); return method; } }
aop拦截请求
package org.sc.goods.manage.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @date: 2019年5月8日 下午3:12:11 */ @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExtRateLimiter { // 以每秒为单位固定的速率值往令牌桶中添加令牌 double permitsPerSecond(); // 在规定的毫秒数中,如果没有获取到令牌的话,则直接走服务降级处理 long timeout(); }
自定义注解,使用直接方法名加ExtRateLimiter注解