ソースを参照

just format code.

deason 4 年 前
コミット
a40e58c59d

+ 257 - 258
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/interceptor/ApiFlowLimitedInterceptor.java

@@ -1,23 +1,5 @@
 package cn.com.qmth.examcloud.web.interceptor;
 
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang.math.RandomUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.servlet.HandlerInterceptor;
-
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.RateLimiter;
-import com.googlecode.aviator.AviatorEvaluator;
-
 import cn.com.qmth.examcloud.commons.util.PropertiesUtil;
 import cn.com.qmth.examcloud.commons.util.Util;
 import cn.com.qmth.examcloud.web.actuator.ApiStatusInfo;
@@ -27,6 +9,21 @@ import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 import cn.com.qmth.examcloud.web.support.ServletUtil;
 import cn.com.qmth.examcloud.web.support.StatusResponse;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.RateLimiter;
+import com.googlecode.aviator.AviatorEvaluator;
+import org.apache.commons.lang.math.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
 
 /**
  * API 流量限制截器
@@ -37,269 +34,271 @@ import cn.com.qmth.examcloud.web.support.StatusResponse;
  */
 public class ApiFlowLimitedInterceptor implements HandlerInterceptor {
 
-	private static final Logger LOG = LoggerFactory.getLogger(ApiFlowLimitedInterceptor.class);
-
-	private static RateLimiter rateLimiter;
+    private static final Logger LOG = LoggerFactory.getLogger(ApiFlowLimitedInterceptor.class);
 
-	private static boolean enable = true;
+    private static RateLimiter rateLimiter;
 
-	private static int allowedRate = 0;
+    private static boolean enable = true;
 
-	private static int minCallRate = 0;
+    private static int allowedRate = 0;
 
-	private static Properties props = new Properties();
+    private static int minCallRate = 0;
 
-	private static Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
+    private static Properties PROPS = new Properties();
 
-	private static Map<String, Integer> permitsPerSecondMap = Maps.newConcurrentMap();
+    private static Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
 
-	static {
-		init();
-	}
+    private static Map<String, Integer> permitsPerSecondMap = Maps.newConcurrentMap();
 
-	private static void init() {
+    static {
+        init();
+    }
 
-		int permitsPerSecond = PropertyHolder.getInt("examcloud.api.permitsPerSecond", 100000);
-		rateLimiter = RateLimiter.create(permitsPerSecond);
+    private static void init() {
 
-		enable = PropertyHolder.getBoolean("examcloud.api.flowLimited.enable", true);
-		allowedRate = PropertyHolder.getInt("examcloud.api.flowLimited.allowedRate", 5);
-		minCallRate = PropertyHolder.getInt("examcloud.api.flowLimited.minCallRate", 10);
+        int permitsPerSecond = PropertyHolder.getInt("examcloud.api.permitsPerSecond", 100000);
+        rateLimiter = RateLimiter.create(permitsPerSecond);
 
-		refreshConfig();
+        enable = PropertyHolder.getBoolean("examcloud.api.flowLimited.enable", true);
+        allowedRate = PropertyHolder.getInt("examcloud.api.flowLimited.allowedRate", 5);
+        minCallRate = PropertyHolder.getInt("examcloud.api.flowLimited.minCallRate", 10);
 
-		for (Entry<Object, Object> entry : props.entrySet()) {
-			String key = (String) entry.getKey();
-			String value = (String) entry.getValue();
+        refreshConfig();
 
-			if (key.endsWith("[S]")) {
-				Integer curPermitsPerSecond = null;
-				try {
-					curPermitsPerSecond = Integer.parseInt(value);
-				} catch (NumberFormatException e) {
-					LOG.error("error value. key= " + key, e);
-					continue;
-				}
+        for (Entry<Object, Object> entry : PROPS.entrySet()) {
+            String key = (String) entry.getKey();
+            String value = (String) entry.getValue();
 
-				if (curPermitsPerSecond < 0) {
-					LOG.error("value is less than 0. key= " + key);
-					continue;
-				}
+            if (key.endsWith("[S]")) {
+                Integer curPermitsPerSecond = null;
+                try {
+                    curPermitsPerSecond = Integer.parseInt(value);
+                } catch (NumberFormatException e) {
+                    LOG.error("error value. key= " + key, e);
+                    continue;
+                }
 
-				if (curPermitsPerSecond > 10000) {
-					LOG.error("value is more than 10000. key= " + key);
-					continue;
-				}
+                if (curPermitsPerSecond < 0) {
+                    LOG.error("value is less than 0. key= " + key);
+                    continue;
+                }
 
-				RateLimiter curRateLimiter = RateLimiter.create(curPermitsPerSecond);
-				limiterMap.put(key, curRateLimiter);
-				permitsPerSecondMap.put(key, curPermitsPerSecond);
-			}
-		}
+                if (curPermitsPerSecond > 10000) {
+                    LOG.error("value is more than 10000. key= " + key);
+                    continue;
+                }
 
-		new Thread(new Runnable() {
-			@Override
-			public void run() {
+                RateLimiter curRateLimiter = RateLimiter.create(curPermitsPerSecond);
+                limiterMap.put(key, curRateLimiter);
+                permitsPerSecondMap.put(key, curPermitsPerSecond);
+            }
+        }
 
-				while (true) {
-					refreshConfig();
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
 
-					Map<String, Integer> updated = Maps.newHashMap();
+                while (true) {
+                    refreshConfig();
 
-					for (Entry<String, Integer> entry : permitsPerSecondMap.entrySet()) {
-						String key = entry.getKey();
-						Integer value = entry.getValue();
+                    Map<String, Integer> updated = Maps.newHashMap();
 
-						String curValue = (String) props.get(key);
-						if (StringUtils.isBlank(curValue)) {
-							continue;
-						}
-						Integer curPermitsPerSecond = null;
-						try {
-							curPermitsPerSecond = Integer.parseInt(curValue);
-						} catch (NumberFormatException e) {
-							LOG.error("error value. key= " + key, e);
-							continue;
-						}
+                    for (Entry<String, Integer> entry : permitsPerSecondMap.entrySet()) {
+                        String key = entry.getKey();
+                        Integer value = entry.getValue();
 
-						if (curPermitsPerSecond < 0) {
-							LOG.error("value is less than 0. key= " + key);
-							continue;
-						}
+                        String curValue = (String) PROPS.get(key);
+                        if (StringUtils.isBlank(curValue)) {
+                            continue;
+                        }
+                        Integer curPermitsPerSecond = null;
+                        try {
+                            curPermitsPerSecond = Integer.parseInt(curValue);
+                        } catch (NumberFormatException e) {
+                            LOG.error("error value. key= " + key, e);
+                            continue;
+                        }
 
-						if (curPermitsPerSecond > 10000) {
-							LOG.error("value is more than 10000. key= " + key);
-							continue;
-						}
+                        if (curPermitsPerSecond < 0) {
+                            LOG.error("value is less than 0. key= " + key);
+                            continue;
+                        }
 
-						if (!value.equals(curPermitsPerSecond)) {
-							RateLimiter curRateLimiter = limiterMap.get(key);
-							curRateLimiter.setRate(curPermitsPerSecond);
-							updated.put(key, curPermitsPerSecond);
-						}
+                        if (curPermitsPerSecond > 10000) {
+                            LOG.error("value is more than 10000. key= " + key);
+                            continue;
+                        }
+
+                        if (!value.equals(curPermitsPerSecond)) {
+                            RateLimiter curRateLimiter = limiterMap.get(key);
+                            curRateLimiter.setRate(curPermitsPerSecond);
+                            updated.put(key, curPermitsPerSecond);
+                        }
+
+                    }
+
+                    permitsPerSecondMap.putAll(updated);
+
+                    Util.sleep(10);
+                }
+            }
+
+        }).start();
+
+    }
+
+    private static void refreshConfig() {
+        try {
+            Properties newProps = new Properties();
+
+            Properties nextProps = new Properties();
+
+            PropertiesUtil.loadFromResource("limited.properties", newProps);
+            for (Entry<Object, Object> entry : newProps.entrySet()) {
+                String key = (String) entry.getKey();
+                String value = (String) entry.getValue();
+                if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
+                    continue;
+                }
+
+                nextProps.put(key.trim(), value.trim());
+            }
+
+            PROPS = nextProps;
+
+        } catch (Exception e) {
+            LOG.error("fail to refresh API config.", e);
+        }
+    }
+
+    @Override
+    public boolean preHandle(HttpServletRequest request,
+                             HttpServletResponse response,
+                             Object handler) throws Exception {
+        if (!enable) {
+            return true;
+        }
+
+        boolean acquired = rateLimiter.tryAcquire();
+        if (!acquired) {
+            if (LOG.isErrorEnabled()) {
+                LOG.error("[Limited]. G.");
+            }
+
+            response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
+            ServletUtil.returnJson(new StatusResponse("503", "limited. G"), response);
+            return false;
+        }
+
+        ApiInfo apiInfo = (ApiInfo) request.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
+        if (null == apiInfo) {
+            return true;
+        }
+
+        ApiStatusInfo apiStatusInfo = null;
+        try {
+            apiStatusInfo = ApiStatusInfoHolder.getApiStatusInfo(apiInfo.getMapping());
+        } catch (Exception e) {
+            // ignore
+        }
+
+        if (null == apiStatusInfo) {
+            return true;
+        }
+
+        String rateLimiterKey = apiInfo.getMapping() + "[S]";
+        RateLimiter limiter = limiterMap.get(rateLimiterKey);
+
+        if (null != limiter) {
+            acquired = limiter.tryAcquire();
+            if (!acquired) {
+
+                if (LOG.isErrorEnabled()) {
+                    LOG.error("[Limited]. S. mapping=" + apiInfo.getMapping());
+                }
+
+                response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
+                ServletUtil.returnJson(new StatusResponse("503", "limited. S"), response);
+                return false;
+            }
+        }
+
+        String expression = null;
+        String expressionKey = apiInfo.getMapping() + "[E]";
+        try {
+            expression = (String) PROPS.get(expressionKey);
+        } catch (Exception e) {
+            LOG.error("error value. key= " + expressionKey, e);
+        }
+
+        if (StringUtils.isBlank(expression)) {
+            return true;
+        }
+        expression = expression.trim();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("expression=" + expression + " ; mapping=" + apiInfo.getMapping());
+        }
+
+        Map<String, Object> env = Maps.newHashMap();
+        env.put("mean", apiStatusInfo.getMean());
+        env.put("max", apiStatusInfo.getMax());
+        env.put("min", apiStatusInfo.getMin());
+        env.put("meanRate", apiStatusInfo.getMeanRate());
+        env.put("oneMinRate", apiStatusInfo.getOneMinuteRate());
+        env.put("errPercent", apiStatusInfo.getErrorPercent());
+        env.put("errMeanRate", apiStatusInfo.getErrorMeanRate());
+
+        boolean limited = false;
+        try {
+            limited = (Boolean) AviatorEvaluator.execute(expression, env, true);
+        } catch (Exception e) {
+            LOG.error("fail to get value of expression. expression= " + expression, e);
+        }
+
+        if (limited) {
+            int random = RandomUtils.nextInt(100);
+            if (random <= allowedRate) {
+                double oneMinuteRate = apiStatusInfo.getOneMinuteRate();
+
+                int curMinCallRate = minCallRate;
+                String minCallRateKey = apiInfo.getMapping() + "[R]";
+                try {
+                    String value = (String) PROPS.get(minCallRateKey);
+                    if (StringUtils.isNotBlank(value)) {
+                        curMinCallRate = Integer.parseInt(value.trim());
+                    }
+                } catch (Exception e) {
+                    LOG.error("error value. key= " + minCallRateKey, e);
+                }
+
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug(
+                            "minCallRate=" + curMinCallRate + "; mapping=" + apiInfo.getMapping());
+                }
+
+                if (oneMinuteRate < curMinCallRate) {
+                    return true;
+                }
+            }
+
+            if (LOG.isErrorEnabled()) {
+                LOG.error("[Limited]. ER. mapping=" + apiInfo.getMapping());
+            }
+
+            response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
+            ServletUtil.returnJson(new StatusResponse("503", "limited. ER"), response);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request,
+                                HttpServletResponse response,
+                                Object handler, Exception ex) throws Exception {
+
+    }
 
-					}
-
-					permitsPerSecondMap.putAll(updated);
-
-					Util.sleep(10);
-				}
-			}
-
-		}).start();
-
-	}
-
-	private static void refreshConfig() {
-		try {
-			Properties newProps = new Properties();
-
-			Properties nextProps = new Properties();
-
-			PropertiesUtil.loadFromResource("limited.properties", newProps);
-			for (Entry<Object, Object> entry : newProps.entrySet()) {
-				String key = (String) entry.getKey();
-				String value = (String) entry.getValue();
-				if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
-					continue;
-				}
-
-				nextProps.put(key.trim(), value.trim());
-			}
-
-			props = nextProps;
-
-		} catch (Exception e) {
-			LOG.error("fail to refresh API config.", e);
-		}
-	}
-
-	@Override
-	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
-			Object handler) throws Exception {
-
-		if (!enable) {
-			return true;
-		}
-
-		boolean acquired = rateLimiter.tryAcquire();
-		if (!acquired) {
-
-			if (LOG.isErrorEnabled()) {
-				LOG.error("[Limited]. G.");
-			}
-
-			response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
-			ServletUtil.returnJson(new StatusResponse("503", "limited. G"), response);
-			return false;
-		}
-
-		ApiInfo apiInfo = (ApiInfo) request
-				.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
-
-		if (null == apiInfo) {
-			return true;
-		}
-
-		ApiStatusInfo apiStatusInfo = null;
-		try {
-			apiStatusInfo = ApiStatusInfoHolder.getApiStatusInfo(apiInfo.getMapping());
-		} catch (Exception e) {
-			// ignore
-		}
-
-		if (null == apiStatusInfo) {
-			return true;
-		}
-
-		String rateLimiterKey = apiInfo.getMapping() + "[S]";
-		RateLimiter limiter = limiterMap.get(rateLimiterKey);
-
-		if (null != limiter) {
-			acquired = limiter.tryAcquire();
-			if (!acquired) {
-
-				if (LOG.isErrorEnabled()) {
-					LOG.error("[Limited]. S. mapping=" + apiInfo.getMapping());
-				}
-
-				response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
-				ServletUtil.returnJson(new StatusResponse("503", "limited. S"), response);
-				return false;
-			}
-		}
-
-		String expression = null;
-		String expressionKey = apiInfo.getMapping() + "[E]";
-		try {
-			expression = (String) props.get(expressionKey);
-		} catch (Exception e) {
-			LOG.error("error value. key= " + expressionKey, e);
-		}
-		if (StringUtils.isBlank(expression)) {
-			return true;
-		}
-		expression = expression.trim();
-
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("expression=" + expression + " ; mapping=" + apiInfo.getMapping());
-		}
-
-		Map<String, Object> env = Maps.newHashMap();
-		env.put("mean", apiStatusInfo.getMean());
-		env.put("max", apiStatusInfo.getMax());
-		env.put("min", apiStatusInfo.getMin());
-		env.put("meanRate", apiStatusInfo.getMeanRate());
-		env.put("oneMinRate", apiStatusInfo.getOneMinuteRate());
-		env.put("errPercent", apiStatusInfo.getErrorPercent());
-		env.put("errMeanRate", apiStatusInfo.getErrorMeanRate());
-		boolean limited = false;
-		try {
-			limited = (Boolean) AviatorEvaluator.execute(expression, env, true);
-		} catch (Exception e) {
-			LOG.error("fail to get value of expression. expression= " + expression, e);
-		}
-		if (limited) {
-
-			int random = RandomUtils.nextInt(100);
-			if (random <= allowedRate) {
-				double oneMinuteRate = apiStatusInfo.getOneMinuteRate();
-
-				int curMinCallRate = minCallRate;
-				String minCallRateKey = apiInfo.getMapping() + "[R]";
-				try {
-					String value = (String) props.get(minCallRateKey);
-					if (StringUtils.isNotBlank(value)) {
-						curMinCallRate = Integer.parseInt(value.trim());
-					}
-				} catch (Exception e) {
-					LOG.error("error value. key= " + minCallRateKey, e);
-				}
-
-				if (LOG.isDebugEnabled()) {
-					LOG.debug(
-							"minCallRate=" + curMinCallRate + "; mapping=" + apiInfo.getMapping());
-				}
-
-				if (oneMinuteRate < curMinCallRate) {
-					return true;
-				}
-			}
-
-			if (LOG.isErrorEnabled()) {
-				LOG.error("[Limited]. ER. mapping=" + apiInfo.getMapping());
-			}
-
-			response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
-			ServletUtil.returnJson(new StatusResponse("503", "limited. ER"), response);
-			return false;
-		}
-		return true;
-	}
-
-	@Override
-	public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
-			Object handler, Exception ex) throws Exception {
-
-	}
 }