package vc.thinker.config.interceptor; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.RateLimiter; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import vc.thinker.exception.CurrentLimitException; import vc.thinker.utils.IpUtils; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * @author : xieshaojun * @date : 2023/1/5 10:32 */ @Order(1) @Aspect @Configuration public class LimitAspect { @Autowired(required = false) HttpServletRequest request; @Autowired private LimitConfig limitConfig; @Autowired private LoadingCache<String, RateLimiter> caches; @Bean public LoadingCache<String, RateLimiter> loadingCache() { LoadingCache<String, RateLimiter> caches = CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterWrite(1, TimeUnit.DAYS) .build(new CacheLoader<>() { @Override public RateLimiter load(String s) { if (ObjectUtils.isEmpty(limitConfig.getSecondLimit())) { return RateLimiter.create(1); }else { return RateLimiter.create(limitConfig.getSecondLimit()); } } }); return caches; } @Pointcut("@annotation(vc.thinker.config.interceptor.ServiceLimit)") public void serviceAspect(){ } @Around("serviceAspect()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); ServiceLimit serviceLimit = method.getAnnotation(ServiceLimit.class); ServiceLimit.LimitType limitType = serviceLimit.limitType(); String key = serviceLimit.key(); Object object; if (Objects.equals(limitType, ServiceLimit.LimitType.IP)) { key = IpUtils.getIpAddr(request); } RateLimiter rateLimiter = caches.get(key); boolean acquire = rateLimiter.tryAcquire(); if (acquire) { object = joinPoint.proceed(); } else { throw new CurrentLimitException("请求太频繁"); } return object; } }