package com.vip.vjtools.vjkit.concurrent.limiter; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import com.google.common.util.concurrent.RateLimiter; public class RateLimiterUtil { /** * 一个用来定制RateLimiter的方法,默认一开始就桶里就装满token。 * * @param permitsPerSecond 每秒允许的请求数,可看成QPS。 * @param maxBurstSeconds 可看成桶的容量,Guava中最大的突发流量缓冲时间,默认是1s, permitsPerSecond * maxBurstSeconds,就是闲置时累积的缓冲token最大值。 */ public static RateLimiter create(double permitsPerSecond, double maxBurstSeconds) throws ReflectiveOperationException { return create(permitsPerSecond, maxBurstSeconds, true); } /** * 一个用来定制RateLimiter的方法。 * * @param permitsPerSecond 每秒允许的请求书,可看成QPS * @param maxBurstSeconds 最大的突发缓冲时间。用来应对突发流量。Guava的实现默认是1s。permitsPerSecond * maxBurstSeconds的数量,就是闲置时预留的缓冲token数量 * @param filledWithToken 是否需要创建时就保留有permitsPerSecond * maxBurstSeconds的token */ public static RateLimiter create(double permitsPerSecond, double maxBurstSeconds, boolean filledWithToken) throws ReflectiveOperationException { Class<?> sleepingStopwatchClass = Class .forName("com.google.common.util.concurrent.RateLimiter$SleepingStopwatch"); Method createStopwatchMethod = sleepingStopwatchClass.getDeclaredMethod("createFromSystemTimer"); createStopwatchMethod.setAccessible(true); Object stopwatch = createStopwatchMethod.invoke(null); Class<?> burstyRateLimiterClass = Class .forName("com.google.common.util.concurrent.SmoothRateLimiter$SmoothBursty"); Constructor<?> burstyRateLimiterConstructor = burstyRateLimiterClass.getDeclaredConstructors()[0]; burstyRateLimiterConstructor.setAccessible(true); // set maxBurstSeconds RateLimiter rateLimiter = (RateLimiter) burstyRateLimiterConstructor.newInstance(stopwatch, maxBurstSeconds); rateLimiter.setRate(permitsPerSecond); if (filledWithToken) { // set storedPermits setField(rateLimiter, "storedPermits", permitsPerSecond * maxBurstSeconds); } return rateLimiter; } private static boolean setField(Object targetObject, String fieldName, Object fieldValue) { Field field; try { field = targetObject.getClass().getDeclaredField(fieldName); } catch (NoSuchFieldException e) { field = null; } Class superClass = targetObject.getClass().getSuperclass(); while (field == null && superClass != null) { try { field = superClass.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { superClass = superClass.getSuperclass(); } } if (field == null) { return false; } field.setAccessible(true); try { field.set(targetObject, fieldValue); return true; } catch (IllegalAccessException e) { return false; } } }