J2ee高并发情况下监听器

引言:在高并发下限制最大并发次数,在web.xml中用过滤器设置參数(最大并发数),并设置其它相关參数。具体见代码。

第一步:配置web.xml配置,不懂的地方解释一下:參数50通过參数名maxConcurrent用在filter的实现类中获取,filter-class就是写的实现类,

url-pattern就是限制并发时间的url。结束!

<filter>
    <filter-name>ConcurrentCountFilter</filter-name>
    <filter-class>com.procure.pass.ConcurrentCountFilter</filter-class>
  	<init-param>
		<param-name>maxConcurrent</param-name>
		<param-value>50</param-value>
	</init-param>
  </filter>
  <filter-mapping>
    <filter-name>ConcurrentCountFilter</filter-name>
    <url-pattern>/a/pass/export</url-pattern>
  </filter-mapping>

第二步:写实现类实现filter,该接口有三个方法,详见代码。

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Servlet Filter implementation class ConcurrentCountFilter
 */
public class ConcurrentCountFilter implements Filter {
	private static Logger log = LoggerFactory.getLogger(ConcurrentCountFilter.class);
	private FilterConfig filterConfig;
	private int maxConcurrent = -1;
	//总计数
	private static AtomicInteger count = new AtomicInteger(0);

	/**
	 * 获取当前并发数
	 * @return
	 */
	public static int get(){
	        return count.get();
	    }
	/**
	 * 添加并发数量
	 * @return
	 */
	 public static int increase(){
	        return count.incrementAndGet();
	    }
	 /**
	  * 降低并发数量
	  * @return
	  */
	 public static int decrement(){
		 return count.decrementAndGet();
	 }

	/**
	 * 初始化
	 */
		public void init(FilterConfig filterConfig) throws ServletException {
			//获取配置的最大并发数量
			String maxStr = filterConfig.getInitParameter("maxConcurrent");
			int num = -1;
			if(maxStr != null && !"".equals(maxStr)){
				num = Integer.parseInt(maxStr);
			}
			if(num >= 1){
				this.maxConcurrent = num;
			}else{
				this.maxConcurrent = -1;
			}
		}
		/**
		 * 过滤主方法
		 */
		public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
			try{
			//添加并发数量
			int num = increase();
			if(maxConcurrent > 0){
				if(maxConcurrent >= num){
					chain.doFilter(request, response);
					log.info("第一次并发数量:"+count.get());
				}else{
					HttpServletResponse res = (HttpServletResponse) response;
					res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,"达到最大并发数限制");
					log.info("达到最大并发数");
					log.info("最大并发数量:"+count.get());
				}
			}else{
				chain.doFilter(request, response);
				log.info("第二次并发数量:"+count.get());
			}
			}finally {
				decrement();
				log.info("减小的并发量:"+count.get());
			}

		}
	/**
	 * 退出销毁
	 */
	public void destroy() {
		this.filterConfig = null;
		log.info("销毁......");
	}
}

代码到此完。

吐槽一下自己在项目中遇到的坑:

1.response.sendError( int, string);在本文代码中为res.sendError当中若直接如本文代码那样会返回一个503server带出来的页面,此页面粗暴及其难看。

在此为了友好通知用户,需做例如以下步骤。在web.xml中做例如以下配置代码:

<error-page>
  	<error-code>503</error-code>
  	<location>/WEB-INF/views/error/503.jsp</location>
  </error-page>

假设在web.xml中配置了上面信息。首先会过滤503(HttpServletResponse.SC_SERVICE_UNAVAILABLE)状态码下的此页面而不会抛server的页面。

当中503.jsp页面需自己完毕在此只贴出来一个演示样例做參考,代码例如以下:

<%
response.setStatus(503);

// 获取异常类
Throwable ex = Exceptions.getThrowable(request);
if (ex != null){
	LoggerFactory.getLogger("500.jsp").error(ex.getMessage(), ex);
}

// 编译错误信息
StringBuilder sb = new StringBuilder("错误信息:\n");
if (ex != null) {
	sb.append(Exceptions.getStackTraceAsString(ex));
} else {
	sb.append("未知错误.\n\n");
}

// 假设是异步请求或是手机端,则直接返回信息
if (Servlets.isAjaxRequest(request)) {
	out.print(sb);
}

// 输出异常信息页面
else {
%>
<%@page import="org.slf4j.Logger,org.slf4j.LoggerFactory"%>
<%@page import="com.xahl_oa.internal.common.web.Servlets"%>
<%@page import="com.xahl_oa.internal.common.utils.Exceptions"%>
<%@page import="com.xahl_oa.internal.common.utils.StringUtils"%>
<%@page contentType="text/html;charset=UTF-8" isErrorPage="true"%>
<%@include file="/WEB-INF/views/include/taglib.jsp"%>
<!DOCTYPE html>
<html>
<head>
	<title>503 - 服务临时不可用</title>
	<%@include file="/WEB-INF/views/include/head.jsp" %>
</head>
<body>
	<div class="container-fluid">
		<div class="page-header"><h1>服务临时不可用请稍后再试.</h1></div>
		<div class="errorMessage">
			错误信息:<%=ex==null?

"未知错误.":StringUtils.toHtml(ex.getMessage())%> <br/> <br/>
			server临时不可用请稍后再试,谢谢。<br/> <br/>
			<a href="javascript:" onclick="history.go(-1);" class="btn">返回上一页</a>  
			<a href="javascript:" onclick="$(‘.errorMessage‘).toggle();" class="btn">查看具体信息</a>
		</div>
		<div class="errorMessage hide">
			<%=StringUtils.toHtml(sb.toString())%> <br/>
			<a href="javascript:" onclick="history.go(-1);" class="btn">返回上一页</a>  
			<a href="javascript:" onclick="$(‘.errorMessage‘).toggle();" class="btn">隐藏具体信息</a>
			<br/> <br/>
		</div>
		<script>try{top.$.jBox.closeTip();}catch(e){}</script>
	</div>
</body>
</html>
<%
} out = pageContext.pushBody();
%>

此页面就比server抛出的页面友好甚多。

本文借鉴自:http://blog.csdn.net/zyb134506/article/details/41692893   在此谢谢此篇博客。

时间: 2024-10-20 03:07:41

J2ee高并发情况下监听器的相关文章

Jackson高并发情况下,产生阻塞

情况:在高并发情况下,查看线程栈信息,有大量的线程BLOCKED. 从线程栈得知,线程栈中出现了阻塞,锁在了com.fasterxml.jackson.databind.ser.SerializerCache.untypedValueSerializer(SerializerCache.java:74)上. 1 "catalina-exec-1453" #1525 daemon prio=5 os_prio=0 tid=0x00007f1010098800 nid=0x2675 wai

WCF服务在高并发情况下报目标积极拒绝的异常处理 z

http://www.cnblogs.com/kklldog/p/5037006.html wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是2种可能: 1:服务器关机或者服务关闭 2:Client调用的端口错误或者服务器防火墙没开相应的端口 但是我们的服务本身是可以调用的,只是偶尔报这个错误,说明并不是这2个问题造成的.继续google,在stackove

关于WCF服务在高并发情况下报目标积极拒绝的异常处理

最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是2种可能: 1:服务器关机或者服务关闭 2:Client调用的端口错误或者服务器防火墙没开相应的端口 但是我们的服务本身是可以调用的,只是偶尔报这个错误,说明并不是这2个问题造成的.继续google,在stackoverflow上看到这样一篇:传送门 1 2 3 4 5 6 7 8 9 10 11

高并发情况下Linux系统及kernel参数优化

众所周知在默认参数情况下Linux对高并发支持并不好,主要受限于单进程最大打开文件数限制.内核TCP参数方面和IO事件分配机制等.下面就从几方面来调整使Linux系统能够支持高并发环境. Iptables相关 如非必须,关掉或卸载iptables防火墙,并阻止kernel加载iptables模块.这些模块会影响并发性能. 单进程最大打开文件数限制 一般的发行版,限制单进程最大可以打开1024个文件,这是远远不能满足高并发需求的,调整过程如下: 在#号提示符下敲入: # ulimit–n 6553

数据库高并发情况下重复值写入的避免 字段组合约束+ SQL SERVER 的SQL语句优化方式小结(转)

10线程同时操作,频繁出现插入同样数据的问题.虽然在插入数据的时候使用了: insert inti tablename(fields....) select @t1,@t2,@t3 from tablename where not exists (select id from tablename where [email protected],[email protected],[email protected]) 当时还是在高并发的情况下无效.此语句也包含在存储过程中.(之前也尝试线判断有无记

高并发情况下Redis 的可用性测试与分析及部署架构说明

一.Redis AOF模式设置 修改配置文件redis.conf参数: appendonly yes # appendfsync always appendfsync everysec # appendfsync no 二.测试方法 创建多线程,其中每一个线程执行一个无限循环向Redis 发送set key-value命令,由于处理器执行一次循环操作的速度非常快,因此这样每一个线程都模拟了一个多并发的情况. <span style="font-size:18px;">cla

Mysql在高并发情况下,防止库存超卖而小于0的解决方案

背景: 本人上次做申领campaign的PHP后台时,因为项目上线后某些时段同时申领的人过多,导致一些专柜的存货为负数(<0),还好并发量不是特别大,只存在于小部分专柜而且一般都是-1的状况,没有造成特别特别严重的后果,但还是要反思了自己的过错. 这次又有新的申领campaign,我翻看了上次的代码逻辑: 正文: [先select后update] beginTranse(开启事务) try{     $result = $dbca->query('select amount from s_st

如何处理高并发情况下的DB插入

插入数据库,在大家开发过程中是很经常的事情,假设我们有这么一个需求: 1.  我们需要接收一个外部的订单,而这个订单号是不允许重复的 2.  数据库对外部订单号没有做唯一性约束 3.  外部经常插入相同的订单,对于已经存在的订单则拒绝处理 对于这个需求,很简单我们会用下面的代码进行处理(思路:先查找数据库,如果数据库存在则直接退出,否则插入) package com.yhj.test; import com.yhj.dao.OrderDao; import com.yhj.pojo.Order;

【转】高并发情况下的单例模式

如果在高并发时候,使用这种单例模式 publci class Singleton{      private static Singleton instance = null;      private Singleton(){} public static Singleton getInstance(){             if(instance == null){                    instance = new Singleton();             }