PersionalRateLimitAspect.java 5.45 KB
package com.yoho.search.aop.downgrade;

import java.lang.reflect.Method;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
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 org.springframework.web.bind.annotation.RequestMapping;

import com.yoho.search.common.filter.YohoHttpServletGetRequestWrapper;
import com.yoho.search.common.SearchDynamicConfigService;

@Component
@Aspect
public class PersionalRateLimitAspect {

	private static final Logger DOWNGRADE = LoggerFactory.getLogger("DOWNGRADE");

	@Autowired
	private PersionalRateLimitService persionalRateLimitService;
	@Autowired
	private SearchDynamicConfigService searchDynamicConfigService;

	@Around("@annotation(com.yoho.search.aop.downgrade.PersionalRateLimit)")
	public Object persionalRateLimit(ProceedingJoinPoint pjp) throws Throwable {
		try {
			//限流是否打开
			if(!searchDynamicConfigService.isPersionalRateLimitOpen()){
				return pjp.proceed();
			}
			MethodSignature signature = (MethodSignature) pjp.getSignature();
			PersionalRateLimit rersionalRateLimit = signature.getMethod().getAnnotation(PersionalRateLimit.class);
			String rateLimitName = this.getPersionalRateLimitName(rersionalRateLimit, pjp);
			Object[] arges = pjp.getArgs();
			for (Object object : arges) {
				if (this.doPersionalRateLimit(object, rersionalRateLimit, rateLimitName)) {
					break;
				}
			}
			return pjp.proceed();
		} catch (Exception e) {
			DOWNGRADE.error(e.getMessage());
			throw e;
		}
	}

	private boolean doPersionalRateLimit(Object object, PersionalRateLimit rateLimit, String rateLimitName) {
		if (object instanceof YohoHttpServletGetRequestWrapper) {
			return this.dealWithGetMethod(object, rateLimit, rateLimitName);
		}
		if (object instanceof Map) {
			return this.dealWithPostMethod(object, rateLimit, rateLimitName);
		}
		return false;
	}

	/**
	 * 处理get请求的方式
	 * 
	 * @param object
	 * @return
	 */
	private boolean dealWithGetMethod(Object object, PersionalRateLimit rateLimit, String rateLimitName) {
		if (!(object instanceof YohoHttpServletGetRequestWrapper)) {
			return false;
		}
		YohoHttpServletGetRequestWrapper yohoHttpServletRequestWrapper = (YohoHttpServletGetRequestWrapper) object;
		String uid = yohoHttpServletRequestWrapper.getParameter("uid");
		if (StringUtils.isBlank(uid) || "0".equalsIgnoreCase(uid)) {
			return false;
		}
		if (rateLimit.isOrderUseable() && StringUtils.isNotBlank(yohoHttpServletRequestWrapper.getParameter("order"))) {
			return false;
		}
		PersionalRateLimitConfig limitConfig = searchDynamicConfigService.getPersionalRateLimitConfig(rateLimitName,rateLimit);
		if (persionalRateLimitService.isPersionalRateLimit(rateLimitName,  limitConfig)) {
			yohoHttpServletRequestWrapper.addParams("uid", new String[] { "0" });
			return true;
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	private boolean dealWithPostMethod(Object object, PersionalRateLimit rateLimit, String rateLimitName) {
		if (!(object instanceof Map)) {
			return false;
		}
		Map<String, Object> map = (Map<String, Object>) object;
		String uid = MapUtils.getString(map, "uid", "");
		if (StringUtils.isBlank(uid) || "0".equalsIgnoreCase(uid)) {
			return false;
		}
		if (rateLimit.isOrderUseable() && StringUtils.isNotBlank(MapUtils.getString(map, "order", ""))) {
			return false;
		}
		PersionalRateLimitConfig limitConfig = searchDynamicConfigService.getPersionalRateLimitConfig(rateLimitName,rateLimit);
		if (persionalRateLimitService.isPersionalRateLimit(rateLimitName,  limitConfig)) {
			map.put("uid", 0);
			return true;
		}
		return false;
	}
	

	/**
	 * @controller层则获取url名称
	 * @service层则获取方法名称
	 * @param pjp
	 * @return
	 */
	private String getPersionalRateLimitName(PersionalRateLimit rersionalRateLimit, ProceedingJoinPoint pjp) {
		if (StringUtils.isNotBlank(rersionalRateLimit.name())) {
			return rersionalRateLimit.name();
		}
		// 1、获取method和class
		Method targetMethod = ((MethodSignature) (pjp.getSignature())).getMethod();
		Class<?> clazz = targetMethod.getDeclaringClass();

		// 2、获取class上的requestMapping
		String classRequestMappingValue = "";
		RequestMapping classRequestMapping = clazz.getDeclaredAnnotation(RequestMapping.class);
		if (classRequestMapping != null && classRequestMapping.value() != null && classRequestMapping.value().length > 0) {
			classRequestMappingValue = classRequestMapping.value()[0];
		}

		// 3、获取method上的requestMapping
		String methodRequestMappingValue = "";
		RequestMapping methodRequestMapping = targetMethod.getDeclaredAnnotation(RequestMapping.class);
		if (methodRequestMapping != null && methodRequestMapping.value() != null && methodRequestMapping.value().length > 0) {
			methodRequestMappingValue = methodRequestMapping.value()[0];
		}

		// 4、获取key
		if (StringUtils.isNotBlank(classRequestMappingValue) || StringUtils.isNotBlank(methodRequestMappingValue)) {
			return classRequestMappingValue + methodRequestMappingValue;
		} else {
			return clazz.getName() + '.' + targetMethod.getName();
		}
	}

}