java高并发处理,限制同一接口访问次数

第一种实现方式 

1、首先在打开拦截器,拦截访问的接口。

package com.zh.config;

import java.nio.charset.Charset;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import com.zh.filter.AuthorizationInterceptor2;
import com.zh.router.Rest;

/**
 * @ClassName: MySpringMvcConfig
 * @Description:拦截器配置
 * @author: renkai721
 * @date: 2018年7月30日 上午11:53:34
 */
@Configuration
public class MySpringMvcConfig extends WebMvcConfigurationSupport {
	@Bean
	public HttpMessageConverter<String> responseBodyConverter() {
		// 设置字符集,不然返回到前台中文乱码
		StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
		return converter;
	}
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		super.configureMessageConverters(converters);
		converters.add(responseBodyConverter());
	}
	
	@Override
    public void addInterceptors(InterceptorRegistry registry) {
		String n1 = Rest.Captcha.Root + Rest.Captcha.getCaptchaImage;
		String n2 = Rest.Login.Root + Rest.Login.checkLoginName;
		String n3 = Rest.Login.Root + Rest.Login.doLogin;
		String n4 = Rest.Login.Root + Rest.Login.logout;
		
        registry.addInterceptor(new AuthorizationInterceptor2()).addPathPatterns("/**").excludePathPatterns(
        		n1,n2,n3,n4);
        super.addInterceptors(registry);
    }


}

2、拦截器里面的处理逻辑

package com.zh.filter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.concurrent.Semaphore;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.zh.util.MsgUtils;
import com.zh.util.USDConstants;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: AuthorizationInterceptor
 * @Description:
 * @author: renkai721
 * @date: 2019年6月14日 下午3:45:47
 */
@Slf4j
public class AuthorizationInterceptor2 extends HandlerInterceptorAdapter {
	// 定义资源的总数量,2表示2个资源总数
	private static int size = 2;
	public static Semaphore welcomeSemaphore = new Semaphore(size);

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		BodyReaderHttpServletRequestWrapper requestWrapper = null;
		if (request instanceof BodyReaderHttpServletRequestWrapper) {
			requestWrapper = (BodyReaderHttpServletRequestWrapper) request;
			// 默认记录后台接口请求日志记录
			String url = requestWrapper.getRequestURL().toString();
			if(url.indexOf("/test/test") != 0) {
				synchronized(welcomeSemaphore) {
					int availablePermits = welcomeSemaphore.availablePermits();
					if (availablePermits > 0) {
						try {
							// 请求占用一个资源
							welcomeSemaphore.acquire(1);
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else {
						log.info("同一秒中,同一接口,只能允许"+size+"个人访问");
						PrintWriter out = response.getWriter();
						String msg = MsgUtils.outJson(USDConstants.BM_CODE_URL_MAX_COUNT);
						out.print(msg);
						out.flush();
						return false;
					}
				}
			}
		}
		return super.preHandle(request, response, handler);
	}
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		BodyReaderHttpServletRequestWrapper requestWrapper;
		if (request instanceof BodyReaderHttpServletRequestWrapper) {
			requestWrapper = (BodyReaderHttpServletRequestWrapper) request;
		}
	}
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}
	/**
	 * 获取请求Body
	 * @param request
	 * @return
	 */
	public static String getBodyString(final ServletRequest request) {
		StringBuilder sb = new StringBuilder();
		InputStream inputStream = null;
		BufferedReader reader = null;
		try {
			inputStream = cloneInputStream(request.getInputStream());
			reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
			String line = "";
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return sb.toString();
	}
	/**
	 * Description: 复制输入流</br>
	 * @param inputStream
	 * @return</br>
	 */
	public static InputStream cloneInputStream(ServletInputStream inputStream) {
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len;
		try {
			while ((len = inputStream.read(buffer)) > -1) {
				byteArrayOutputStream.write(buffer, 0, len);
			}
			byteArrayOutputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
		return byteArrayInputStream;
	}
}

3、BodyReaderHttpServletRequestWrapper

package com.zh.filter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.StringUtils;

/**
 * @ClassName: BodyReaderHttpServletRequestWrapper
 * @Description:
 * @author: renkai721
 * @date: 2019年10月15日 下午2:24:17
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
	private final byte[] body;

	public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
		super(request);
		body = readBytes(request.getReader(), "utf-8");
	}
	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(getInputStream()));
	}
	@Override
	public ServletInputStream getInputStream() throws IOException {
		final ByteArrayInputStream bais = new ByteArrayInputStream(body);
		return new ServletInputStream() {
			@Override
			public boolean isFinished() {
				return false;
			}
			@Override
			public boolean isReady() {
				return false;
			}
			@Override
			public void setReadListener(ReadListener listener) {
			}
			@Override
			public int read() throws IOException {
				return bais.read();
			}
		};
	}
	/**
	 * 通过BufferedReader和字符编码集转换成byte数组
	 * @param br
	 * @param encoding
	 * @return
	 * @throws IOException
	 */
	private byte[] readBytes(BufferedReader br, String encoding) throws IOException {
		String str = null, retStr = "";
		while ((str = br.readLine()) != null) {
			retStr += str;
		}
		if (StringUtils.isNotBlank(retStr)) {
			return retStr.getBytes(Charset.forName(encoding));
		}
		return null;
	}
}

4、我们写一个test接口

package com.zh.crs.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.zh.common.MyBaseController;
import com.zh.router.Rest;
import com.zh.util.MsgUtils;

/**
 * @ClassName: TestController
 * @Description: 生成验证码
 * @author: renkai721
 * @date: 2019年3月28日 上午9:31:21
 */
@RestController
@RequestMapping(Rest.Test.Root)
public class TestController2 extends MyBaseController {
	@RequestMapping(value = Rest.Test.test, method = RequestMethod.GET)
	@ResponseBody
	public synchronized String test() {
		try {
			// 处理自己的逻辑
			Thread.sleep(1);
			// 逻辑处理完了就要释放一个资源
//			AuthorizationInterceptor.welcomeSemaphore.release(1);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return MsgUtils.outJsonSuccess();
	}
}

5、运行结果

2019-10-15 14:15:15 org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/fxcrs] [173] | Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-10-15 14:15:15 org.springframework.web.servlet.DispatcherServlet [524] | Initializing Servlet 'dispatcherServlet'
2019-10-15 14:15:15 org.springframework.web.servlet.DispatcherServlet [546] | Completed initialization in 10 ms
2019-10-15 14:15:15 com.zh.filter.AuthorizationInterceptor2 [57] | 同一秒中,同一接口,只能允许2个人访问
2019-10-15 14:15:15 com.zh.util.MsgUtils [195] | {"errorText":"同一接口访问上限,请稍后再试","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"bm_code_url_max_count","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:15 com.zh.util.MsgUtils [222] | {"errorText":"操作成功","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"success","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:15 com.zh.util.MsgUtils [222] | {"errorText":"操作成功","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"success","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:15 com.zh.filter.AuthorizationInterceptor2 [57] | 同一秒中,同一接口,只能允许2个人访问
2019-10-15 14:15:15 com.zh.util.MsgUtils [195] | {"errorText":"同一接口访问上限,请稍后再试","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"bm_code_url_max_count","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:15 com.zh.filter.AuthorizationInterceptor2 [57] | 同一秒中,同一接口,只能允许2个人访问
2019-10-15 14:15:15 com.zh.util.MsgUtils [195] | {"errorText":"同一接口访问上限,请稍后再试","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"bm_code_url_max_count","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:15 com.zh.filter.AuthorizationInterceptor2 [57] | 同一秒中,同一接口,只能允许2个人访问
2019-10-15 14:15:15 com.zh.util.MsgUtils [195] | {"errorText":"同一接口访问上限,请稍后再试","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"bm_code_url_max_count","sEcho":"","iDisplayStart":0}
2019-10-15 14:15:16 com.zh.filter.AuthorizationInterceptor2 [57] | 同一秒中,同一接口,只能允许2个人访问
2019-10-15 14:15:16 com.zh.util.MsgUtils [195] | {"errorText":"同一接口访问上限,请稍后再试","iTotalRecords":0,"aaData":"","iTotalDisplayRecords":0,"errorCode":"bm_code_url_max_count","sEcho":"","iDisplayStart":0}

备注:大家要注意test接口中注释的那一段话,其中Thread.sleep(1);是我做测试用的,实际中是没有这句话的,实际中应该是自己的业务逻辑,也当然不止1毫秒。下面的释放资源的代码,实际中需要放开,因为一个用户的请求处理完了,下一个用户就可以访问了,所以需要释放资源。

第二种实现方式

1、拦截器中使用map来保存请求的url

// 资源总数
	private static int size = 2;
	public static ConcurrentHashMap<String, Integer> urlCount = new ConcurrentHashMap<String, Integer>();
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		BodyReaderHttpServletRequestWrapper requestWrapper = null;
		if (request instanceof BodyReaderHttpServletRequestWrapper) {
			// 签名处理过程 start....
			requestWrapper = (BodyReaderHttpServletRequestWrapper) request;
			// 签名处理过程 end....
			// 默认记录后台接口请求日志记录
			String url = requestWrapper.getRequestURL().toString();
			if(url.indexOf("/test/welcome") != 0) {
				synchronized(urlCount) {
					String f = "yyyyMMddHHmmss";
					String key = LocalDateTime.now().format(DateTimeFormatter.ofPattern(f)) + "_" + "/test/welcome";
					log.info("key=" + key);
					Integer v = urlCount.get(key);
					log.info("v=" + v);
					if (null != v) {
						v++;
						if (v > size) {
							log.info("同一秒中,同一接口,只能允许"+size+"个人访问");
							PrintWriter out = response.getWriter();
							String msg = MsgUtils.outJson(USDConstants.BM_CODE_URL_MAX_COUNT);
							out.print(msg);
							out.flush();
							return false;
						}
						urlCount.put(key, v);
					} else {
						urlCount.put(key, 1);
					}
				}
			}
		}
		return super.preHandle(request, response, handler);
	}

2、具体的welcome接口逻辑

@RequestMapping(value = Rest.Test.welcome, method = RequestMethod.GET)
	@ResponseBody
	public synchronized  String welcome() {
		try {
			// 处理自己的逻辑
			Thread.sleep(1);
//			String f = "yyyyMMddHHmmss";
//			String key = LocalDateTime.now().format(DateTimeFormatter.ofPattern(f)) + "_" + "/test/welcome";
//			Integer v = AuthorizationInterceptor.urlCount.get(key);
//			// 逻辑处理完,释放一个资源
//			v--;
//			System.out.println("逻辑处理完成释放一个资源,key="+key+",value="+v);
//			AuthorizationInterceptor.urlCount.put(key, v);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return MsgUtils.outJsonSuccess();
	}

备注:在实际的场景中welcome里面的释放资源代码需要放开。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
随着当今信息技术的高速发展,人们日常生产生活中产生的数据量呈现出爆 发式增长。因此,对于海量数据集的处理已成为数据挖掘技术的主要挑战。而如 何能以高性价比的方式挖掘到有价值的信息是目前数据挖掘研究的新课题。 GPu通用计算技术的R益成熟为数据挖掘技术的发展注入了新的动力。 GPU通过与CPu截然不同的发展路线,由当初的专用图形处理器一步步走进今 天的通用计算领域,并且正在向传统架构的超级计算机发起挑战。很显然,数 据挖掘这类计算密集型应用也必将受益于现代GPU所提供的廉价大规模并行计 算能力。 关联规则是数据挖掘的重要技术之一,而其中的频繁项集计算任务又是整 个算法的核心,研究如何利用GPu通用计算技术来加速频繁项集挖掘具有一定 的理论与实际意义。本文通过分析与总结过去关于频繁项集挖掘的研究成果, 设计了一种基于OpencL的CPU+GPU异构执行的挖掘算法,利用OpenCL创 建大规模并发线程来加速计算Apriori算法中的计算密集部分。实验采用OpenCL 的Java绑定接口来具体实现,并选择了同一级别的CPu与GPu用于改进后算 法与原算法的性能对比测试。实验结果表明,改进算法对于稀疏数据集有更好 的加速性能,并且随着支持度的降低,加速比呈现扩大趋势,最高达到约20倍。 另外,本文初步讨论并实验了利用0penCL的LocalMemory机制来对事务数据 的访问作进一步优化。不过,最后的测试结果表明这种改进仅对稠密数据集产 生了约10%的性能提升。本文在最后还指出了一些未来值得进一步研究与改进 的方向。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

renkai721

谢谢您的打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值