1.自定義註解
package com.com.hangzhou.executor.ratelimiter.annotion;
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
double limitNum() default 10;
}
2.自定義aop實現類
package com.com.hangzhou.executor.ratelimiter;
import com.com.hangzhou.executor.ratelimiter.annotion.RateLimit;
import com.google.common.util.concurrent.RateLimiter;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
/**
* 自定義註解限流切面 @RateLimit
*/
@Component
public class RateLimiterAop implements MethodInterceptor {
/**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(RateLimiterAop.class);
/**
* key -> methodName value -> RateLimiter
*/
private ConcurrentHashMap<String, RateLimiter> concurrentHashMap = new ConcurrentHashMap<>();
@Autowired
private HttpServletResponse response;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//獲取執行方法
Method method = invocation.getMethod();
//獲取方法標註的註解@RateLimit
RateLimit annotation = method.getAnnotation(RateLimit.class);
//未標註的方法不需要攔截限流處理
if (annotation == null) {
return invocation.proceed();
}
//獲取註解配置的限流值
double limitNum = annotation.limitNum();
//獲取方法名
String methodName = method.getName();
if (!concurrentHashMap.containsKey(methodName)) {
concurrentHashMap.put(methodName, RateLimiter.create(limitNum));
}
//獲取限流RateLimiter令牌桶算法
RateLimiter rateLimiter = concurrentHashMap.get(methodName);
//嘗試獲取token 獲取成功執行,打印日誌,未獲取到給於友好的提示
if (rateLimiter.tryAcquire()) {
Object result = invocation.proceed();
LOGGER.info("執行的Controller" + method.getDeclaringClass().getName()
+ "執行的方法名:" + methodName +
"執行的結果:" + ToStringBuilder.reflectionToString(result));
} else {
outWriteResultErrorMsg("網絡繁忙,請稍後重試");
}
return invocation.proceed();
}
private void outWriteResultErrorMsg(String errorMsg) {
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(errorMsg.getBytes(Charset.defaultCharset()));
} catch (IOException e) {
LOGGER.warn("IO異常" + e);
throw new RuntimeException("自定義異常");
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
LOGGER.warn("IO異常" + e);
throw new RuntimeException("自定義異常");
}
}
}
}
}
3.自定義controller
package com.com.hangzhou.executor.ratelimiter;
import com.com.hangzhou.executor.ratelimiter.annotion.RateLimit;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class RateLimiterController {
@RequestMapping("/test")
@ResponseBody
@RateLimit(limitNum = 20)
public Object test() {
return "success";
}
}
4.自定義xml配置
<bean id="rateLimiterAop" class="com.com.hangzhou.executor.ratelimiter.RateLimiterAop"/>
<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>rateLimiterAop</value>
</list>
</property>
<property name="beanNames">
<list>
<value>*Controller</value>
</list>
</property>
</bean>
spring aop自定義實現RateLimiter @Pointcut @Aroud
package com.hangzhou.executor.aop.ratelimiter;
import com.com.hangzhou.executor.ratelimiter.annotion.RateLimit;
import com.google.common.util.concurrent.RateLimiter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
@Scope
//配置@Scope默認爲單例
public class RateLimiterAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(RateLimiterAspect.class);
private ConcurrentHashMap<String, RateLimiter> concurrentHashMap = new ConcurrentHashMap<>();
@Autowired
private HttpServletResponse response;
@Pointcut(value = "@annotation(com.com.hangzhou.executor.ratelimiter.annotion.RateLimit)")
public void rateLimiterPointCut() {
}
@Around(value = "rateLimiterPointCut()")
public Object executeRateLimiter(ProceedingJoinPoint joinPoint) {
Object result = null;
//獲取執行的方法
Signature signature = joinPoint.getSignature();
//cast method type
MethodSignature methodSignature = (MethodSignature) signature;
//獲取方法
Method method = methodSignature.getMethod();
//獲取method中配置的註解
RateLimit rateLimit = method.getAnnotation(RateLimit.class);
//獲取不到,說明不需要限流處理,直接放行
if (rateLimit == null) {
try {
result = joinPoint.proceed();
//打印日誌
LOGGER.info(ToStringBuilder.reflectionToString(result));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
//獲取配置的限流數
double limitNum = rateLimit.limitNum();
//獲取方法名 作爲key
String methodName = method.getName();
if (!concurrentHashMap.containsKey(methodName)) {
concurrentHashMap.put(methodName, RateLimiter.create(limitNum));
}
//獲取限流RateLimiter令牌桶算法
RateLimiter rateLimiter = concurrentHashMap.get(methodName);
//嘗試獲取token 獲取成功執行,打印日誌,未獲取到給於友好的提示
if (rateLimiter.tryAcquire()) {
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
LOGGER.info("執行的Controller" + method.getDeclaringClass().getName()
+ "執行的方法名:" + methodName +
"執行的結果:" + ToStringBuilder.reflectionToString(result));
} else {
outWriteResultErrorMsg("網絡繁忙,請稍後重試");
}
return result;
}
private void outWriteResultErrorMsg(String msg) {
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(msg.getBytes(Charset.defaultCharset()));
} catch (IOException e) {
LOGGER.warn("IO異常" + e);
throw new RuntimeException("自定義異常");
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
LOGGER.warn("IO異常" + e);
throw new RuntimeException("自定義異常");
}
}
}
}
}