赞
踩
部分场景需要动态修改注解的值。例如,我们使用自定义注解控制接口流量,如果需要动态修改流量值,可以使用反射的方法实现。
该部分代码主要是基于流量控制的功能demo,使用反射动态修改@RateLimit注解达到动态修改流量的目的。此章节节选了反射修改值的代码予以分享。
- import com.hz.common.aop.limit.RateLimit;
-
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import java.util.Map;
-
- /**
- * @author pp_lan
- * @date 2024/2/3
- */
- public class ReflectUtils {
-
- private ReflectUtils() {
- }
-
- public static void dynamicLocation(RateLimit rateLimit, String fileName, Object fieldValue) throws IllegalAccessException, NoSuchFieldException {
-
- if (rateLimit == null) {
- return;
- }
-
- InvocationHandler invocationHandler = Proxy.getInvocationHandler(rateLimit);
- Class<? extends InvocationHandler> aClass = invocationHandler.getClass();
-
- Field memberValues = aClass.getDeclaredField("memberValues");
- memberValues.setAccessible(true);
- Map<String, Object> menberValueMap = (Map<String, Object>) memberValues.get(invocationHandler);
- menberValueMap.put(fileName, fieldValue);
- }
- }
- import java.lang.annotation.*;
-
- /**
- * @author pp_lan
- */
- @Documented
- @Inherited
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface RateLimit {
-
- /**
- * 名称
- *
- * @return
- */
- String name();
-
- /**
- * 每分钟限流数量
- *
- * @return
- */
- int limitNum();
-
- }
切面中需要动态获取注解
- @Component
- public class RateLimitAspect {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(RateLimitAspect.class);
-
- private ConcurrentHashMap<String, RateLimiter> limitMap = new ConcurrentHashMap<>();
-
- @Pointcut("@annotation(com.hz.common.aop.limit.RateLimit) && @annotation(rateLimit)")
- public void pointCut(RateLimit rateLimit){}
-
- @Around(value = "pointCut(rateLimit)")
- public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
-
- // 此处动态获取注解值取代初始化的RateLimit值
- Object target = joinPoint.getTarget();
- MethodSignature sig = (MethodSignature) joinPoint.getSignature();
- Method currentMethod = target.getClass().getMethod(sig.getName(), sig.getParameterTypes());
- RateLimit newRateLimit = currentMethod.getAnnotation(RateLimit.class);
- LOGGER.info("[限流器{}]{}", newRateLimit.name(), newRateLimit.limitNum());
- boolean isLimited = limitByKey(newRateLimit.name(), newRateLimit.limitNum());
- if (isLimited) {
- throw new RateLimitException(String.format("【限流了】%s", newRateLimit.name()));
- }
-
- return joinPoint.proceed();
- }
-
- /**
- * 是否被限流
- *
- * @param key
- * @param limitNum
- * @return
- */
- private boolean limitByKey(String key, Integer limitNum) {
- ...
- }
-
- }
5-7行获取注解,并修改注解中属性的值
- @RequestMapping("/updateLimitRate")
- public Response editLimitRate(Integer methodType, Integer limitNum) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
-
- String methodName = methodType == 1 ? "queryAllUser": "test";
- Method method = UserService.class.getMethod(methodName);
- RateLimit annotation = method.getAnnotation(RateLimit.class);
- ReflectUtils.dynamicLocation(annotation, "limitNum", limitNum);
- return Response.ok();
- }
不再限流,接口可以继续正常访问了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。