提交 f30bb862 编写于 作者: 希川's avatar 希川

<feat>: 添加限流器支持功能,基于 guava 的 RateLimiter 实现

上级 d74b86b5
......@@ -75,6 +75,13 @@
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
<build>
......
package cn.noexception.ratelimiter;
import com.google.common.util.concurrent.RateLimiter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Constants
*
* @author 吕滔
* @Date 2021/11/16 14:47
*/
public class Constants {
public static Map<String, RateLimiter> rateLimiterMap = Collections.synchronizedMap(new HashMap<String, RateLimiter>());
}
package cn.noexception.ratelimiter;
import cn.noexception.container.factory.stereotype.Cube;
import cn.noexception.ratelimiter.annotation.DoRateLimiter;
import cn.noexception.ratelimiter.valve.IValveService;
import cn.noexception.ratelimiter.valve.impl.RateLimiterValve;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
/**
* DoRateLimiterPoint
*
* @author 吕滔
* @Date 2021/11/16 14:19
*/
@Cube
public class DoRateLimiterPoint {
@Pointcut("@annotation(cn.noexception.ratelimiter.annotation.DoRateLimiter)")
public void aopPoint() {
}
@Around("aopPoint() && @annotation(doRateLimiter)")
public Object doRouter(ProceedingJoinPoint jp, DoRateLimiter doRateLimiter) throws Throwable {
IValveService valveService = new RateLimiterValve();
return valveService.accept(jp, getMethod(jp), doRateLimiter, jp.getArgs());
}
private Method getMethod(JoinPoint joinPoint) throws NoSuchMethodException {
Signature sig = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
return joinPoint.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
}
package cn.noexception.ratelimiter.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* DoRateLimiter
* 自定义限流器注解
*
* @author 吕滔
* @Date 2021/11/16 14:19
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DoRateLimiter {
double rate() default 1; // 限流许可量
String returnJson() default ""; // 返回结果信息
}
package cn.noexception.ratelimiter.valve;
import cn.noexception.ratelimiter.annotation.DoRateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import java.lang.reflect.Method;
/**
* IValveService
*
* @author 吕滔
* @Date 2021/11/16 14:22
*/
public interface IValveService {
Object accept(ProceedingJoinPoint jp, Method method, DoRateLimiter doRateLimiter, Object[] args) throws Throwable;
}
package cn.noexception.ratelimiter.valve.impl;
import cn.hutool.json.JSONUtil;
import cn.noexception.ratelimiter.Constants;
import cn.noexception.ratelimiter.annotation.DoRateLimiter;
import cn.noexception.ratelimiter.valve.IValveService;
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import java.lang.reflect.Method;
/**
* RateLimiterValve
* 限流调用服务包装
*
* @author 吕滔
* @Date 2021/11/16 14:22
*/
public class RateLimiterValve implements IValveService {
@Override
public Object accept(ProceedingJoinPoint jp, Method method, DoRateLimiter doRateLimiter, Object[] args) throws Throwable {
// 判断是否开启限流器
if (0 == doRateLimiter.rate()) return jp.proceed();
String clazzName = jp.getTarget().getClass().getName();
String methodName = method.getName();
String key = clazzName + "." + methodName;
if (null == Constants.rateLimiterMap.get(key)) {
Constants.rateLimiterMap.put(key, RateLimiter.create(doRateLimiter.rate()));
}
RateLimiter rateLimiter = Constants.rateLimiterMap.get(key);
if (rateLimiter.tryAcquire()) {
return jp.proceed();
}
return JSONUtil.parse(doRateLimiter.returnJson()).toBean(method.getReturnType());
}
}
......@@ -121,7 +121,8 @@ public class AopTest {
public void test_inject() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-inject.xml");
IUserService userService = applicationContext.getBean("userService", IUserService.class);
System.out.println("测试结果:" + userService.queryUserInfo());
System.out.println("测试结果1:" + userService.queryUserInfo());
System.out.println("测试结果2:" + userService.queryUserInfo());
}
......
......@@ -3,6 +3,7 @@ package cn.noexception.test.bean;
import cn.noexception.container.factory.annotation.Inject;
import cn.noexception.container.factory.annotation.InputValue;
import cn.noexception.container.factory.stereotype.Cube;
import cn.noexception.ratelimiter.annotation.DoRateLimiter;
import java.util.Random;
......@@ -21,6 +22,7 @@ public class UserService implements IUserService {
@Inject
private UserDao userDao;
@DoRateLimiter(rate = 1, returnJson = "{\"code\":\"1111\",\"info\":\"调用方法超过最大次数,限流返回!\"}")
@Override
public String queryUserInfo() {
try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册