并发限流器

package com.richinfo.sipop.web.admin.aop;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

/**
 * 并发限流器, 可限流最大接口数为2000(默认,可在配置文件中用customRatelimiter.cacheSize.maxSize指定),
 * 每个接口的最大并发数为100(默认,可在配置文件中用customRatelimiter.thread.maxSize指定),
 * 不需要限流时,用@NotConcurrentLimit注解类或者方法。
 * @see com.richinfo.sipop.common.annotation.NotConcurrentLimit
 * 
 * @author WangZhJ 2018年5月25日
 */
@Aspect
@Component
public class CustomRatelimiter implements InitializingBean{

	private Logger logger = LoggerFactory.getLogger(CustomRatelimiter.class);
	
	/**
	 * 可限流接口最大数目,可配置,默认为2000(定义占用内存上限)
	 */
	@Value("${customRatelimiter.cacheSize.maxSize:2000}")
	private int cacheSize;

	private static final int defaultCacheSize = 2000;
	/**
	 * 允许每秒最大并发数,可配置,默认为100
	 */
	@Value("${customRatelimiter.thread.maxSize:100}")
	private int limit;

	/**
	 * key:方法完整签名+当前秒数,value:并发数
	 */
	private LoadingCache counter;

	@Override
	public void afterPropertiesSet() throws Exception {
		logger.info("----->限流器初始化开始");
		logger.info("----->配置文件中用customRatelimiter.cacheSize.maxSize指定的流器缓存大小(可限流接口数为{}",cacheSize);


		try {
			//配置异常时,设为2000
			cacheSize = Integer.parseInt(String.valueOf(cacheSize));
		} catch (Exception e) {
			cacheSize = defaultCacheSize;
			logger.error("----->解析配置文件中用customRatelimiter.cacheSize.maxSize指定的流器缓存大小(可限流接口数出错",e);
		}
		
		//小于0时设为2000
		if(cacheSize <= 0) {
			cacheSize = defaultCacheSize;
		}
		logger.info("----->限流器缓存大小(可限流接口数)初始化为{}", cacheSize);

		counter = CacheBuilder.newBuilder().maximumSize(cacheSize)
					.expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader() {
						@Override
						public AtomicLong load(String key) throws Exception {
							return new AtomicLong(0);
						}
					});
		logger.info("----->限流器缓存大小(可限流接口数)初始化开始结束");

	}
	
	/**
	 * 切入点为:sipop-web-admin工程下controller层的方法:方法上有@RequestMapping注解
	 * 并且不被@NotConcurrentLimit注解的类和方法
	 */
	@Pointcut("execution(public * com.richinfo.sipop.web.admin.controller..*.*(..)) "
			+ " && @annotation(org.springframework.web.bind.annotation.RequestMapping) "
			+ " && !@annotation(com.richinfo.sipop.common.annotation.NotConcurrentLimit) "
			+ " && !@target(com.richinfo.sipop.common.annotation.NotConcurrentLimit)")
	public void limitPointer() {
	}

	// @Before("limitPointer()")
	// public void doBefore(JoinPoint joinPoint){
	// System.out.println(this.hashCode()+" "+this);
	// }

	@Around("limitPointer()")
	public Object arround(ProceedingJoinPoint pjp) {
		if (logger.isDebugEnabled()) {
			logger.debug("----->限流开始:");
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			// URL
			logger.debug("----->url={}", request.getRequestURI());
			// method
			logger.debug("----->method={}", request.getMethod());
			// ip
			logger.debug("----->ip={}", request.getRemoteAddr());
			// 类方法
			logger.debug("----->class={} and method name = {}", pjp.getSignature().getDeclaringTypeName(),
					pjp.getSignature().getName());
			// 参数
			logger.debug("----->params={}", pjp.getArgs());
			// 方法完整签名
			logger.debug("----->method toLongString={}", pjp.getSignature().toLongString());
		}

		// 得到方法签名
		String method = pjp.getSignature().toLongString();
		// 得到当前秒
		long currentSeconds = System.currentTimeMillis() / 1000;
		String key = method + "." + currentSeconds;
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("----->"+key + "时的并发数为:" + counter.get(key));
			}
			if (counter.get(key).incrementAndGet() > limit) {
				logger.error("----->已超过最大并发数");
				return null;
			}
		} catch (ExecutionException e) {
			logger.error("----->限流出错:", e);
		}
		try {
			Object o = pjp.proceed();
			return o;
		} catch (Throwable e) {
			logger.error("----->方法执行出错:method toLongString={}", pjp.getSignature().toLongString());
			return null;
		}
	}

	

}
package com.richinfo.sipop.common.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 不需要进行并发控制时加此注解;
 * 在类上加注解,对该类中所有方法都不限流;
 * 在方法上加注解,对该方法不限流;
 * 该注解不支持继承。
 * 
 * @author WangZhJ 2018年5月25日
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotConcurrentLimit {

}


你可能感兴趣的:(高并发)