跳到正文
Arlen

Spring Interceptor —— URI并发拦截器

2016-09-01

最近做供应商API对接时,因为对方数据量比较大,采用的方案是分批次导入。那么对方分批次就意味着我们这边的并发压力,为了不让弱不禁风的tomcat挂掉,只能采用拦截器的办法,为每个URI,同一个用户同时的并发数强制限制为5。

拦截器java代码:

public class ConcurrentNumberInterceptor extends BaseController implements HandlerInterceptor {
 
    private final static int MAX_THREAD_SIZE = 2;
    private final static String DIV_STR = "_";
    private final static String LOCKER = "locker";
    private final static Logger logger = LoggerFactory.getLogger(ConcurrentNumberInterceptor.class);
 
    private final static ConcurrentHashMap<String, List<String>> uriMap = new ConcurrentHashMap<String, List<String>>();
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
 
        String requestPath = request.getRequestURI();
        EntrustCompany loginUser = getLoginUserInfo(request);
        if (loginUser == null) {
            logger.info("并发拦截开始,当前无登录用户信息,返回");
            return true;
        }
        String orgCode = getLoginUserInfo(request).getOrgCode();
        logger.info("企业["+orgCode+"]请求["+requestPath+"]并发拦截开始");
        String key = orgCode + DIV_STR + requestPath;
        synchronized (LOCKER) {
            if (!uriMap.containsKey(key)) {
                logger.info("["+requestPath+"]当前无线程运行");
                uriMap.put(key, new ArrayList<String>());
            } else {
                logger.info("["+requestPath+"]当前运行线程"+JSON.toJSONString(uriMap.get(key))+"");
                if (uriMap.get(key).size() >= MAX_THREAD_SIZE) {
                    String resStr = JSON.toJSONString(new ResponseVo(false, "当前并发数超过限定值["+MAX_THREAD_SIZE+"],请稍后重试", ErrorCode.API_ERROR, null));
                    TRestUtil.write(response, resStr);
                    logger.info("["+requestPath+"]当前运行线程数超过限制"+MAX_THREAD_SIZE+"个");
                    return false;
                }
            }
            uriMap.get(key).add(Thread.currentThread().getName());
        }
        return true;
    }
 
    // after handler invoked
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        String requestPath = request.getRequestURI();
        EntrustCompany loginUser = getLoginUserInfo(request);
        if (loginUser == null) {
            logger.info("并发拦截结束,当前无登录用户信息,返回");
        }
        String orgCode = getLoginUserInfo(request).getOrgCode();
        logger.info("企业["+orgCode+"]请求["+requestPath+"]并发拦截结束");
        String key = orgCode + DIV_STR + requestPath;
        synchronized (LOCKER) {
            if (uriMap.containsKey(key)) {
                String threadName = Thread.currentThread().getName();
                logger.info("并发拦截结束,删除当前线程标记["+threadName+"]");
                if (!CollectionUtils.isEmpty(uriMap.get(key))) {
                    uriMap.get(key).remove(threadName);
                }
            }
        }
    }
 
    // after view rendered
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }
 
}

dispacher-servlet.xml中的配置

<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/chb-api/**"/>
            <bean id="concurrentInterceptor" class="com.hongkun.greenpass.exchange.basic.web.ConcurrentNumberInterceptor"></bean>
        </mvc:interceptor>
</mvc:interceptors>

分享到: 更多