diff --git a/pom.xml b/pom.xml
index 53c9a26e4d..f4e373ad80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -343,6 +343,12 @@
${junit.version}
test
+
+ org.springframework
+ spring-mock
+ 2.0.8
+ test
+
org.apache.derby
derby
diff --git a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java
index ef308ef53f..dc3aa606fc 100644
--- a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java
+++ b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java
@@ -29,18 +29,26 @@ import com.alibaba.druid.util.ServletPathMatcher;
public class WebStatFilter implements Filter {
- private final static Log LOG = LogFactory.getLog(WebStatFilter.class);
+ public final static String PARAM_NAME_SESSION_STAT_ENABLE = "sessionStatEnable";
+ public final static String PARAM_NAME_SESSION_STAT_MAX_COUNT = "sessionStatMaxCount";
+ public static final String PARAM_NAME_EXCLUSIONS = "exclusions";
- private WebAppStat webAppStat = null;
- private WebStatFilterContextListener statFilterContextListener = new WebStatFilterContextListener();
+ public final static int DEFAULT_MAX_STAT_SESSION_COUNT = 1000 * 100;
+
+ private final static Log LOG = LogFactory.getLog(WebStatFilter.class);
+
+ private WebAppStat webAppStat = null;
+ private WebStatFilterContextListener statFilterContextListener = new WebStatFilterContextListener();
/**
* PatternMatcher used in determining which paths to react to for a given request.
*/
- protected PatternMatcher pathMatcher = new ServletPathMatcher();
+ protected PatternMatcher pathMatcher = new ServletPathMatcher();
- private final String EXCLUSIONS = "exclusions";
private Set excludesPattern;
- private boolean createSession = false;
+
+ private boolean sessionStatEnable = true;
+ private int sessionStatMaxCount = DEFAULT_MAX_STAT_SESSION_COUNT;
+ private boolean createSession = false;
private String contextPath;
@@ -86,6 +94,7 @@ public class WebStatFilter implements Filter {
if (sessionStat != null) {
sessionStat.setLastAccessTimeMillis(startMillis);
sessionStat.reacord(nanoSpan);
+ sessionStat.incrementRequestCount();
}
}
@@ -94,10 +103,14 @@ public class WebStatFilter implements Filter {
}
public WebSessionStat getSessionStat(HttpServletRequest request) {
+ if (!isSessionStatEnable()) {
+ return null;
+ }
+
WebSessionStat sessionStat = null;
String sessionId = getSessionId(request);
if (sessionId != null) {
- sessionStat = webAppStat.getSessionStat(sessionId);
+ sessionStat = webAppStat.getSessionStat(sessionId, true);
}
if (sessionStat != null) {
@@ -140,10 +153,10 @@ public class WebStatFilter implements Filter {
if (excludesPattern == null) {
return false;
}
-
+
if (contextPath != null && requestURI.startsWith(contextPath)) {
requestURI = requestURI.substring(contextPath.length());
- if(!requestURI.startsWith("/")) {
+ if (!requestURI.startsWith("/")) {
requestURI = "/" + requestURI;
}
}
@@ -153,7 +166,7 @@ public class WebStatFilter implements Filter {
return true;
}
}
-
+
return false;
}
@@ -163,16 +176,41 @@ public class WebStatFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
- String exclusions = config.getInitParameter(EXCLUSIONS);
- if (exclusions != null && exclusions.trim().length() != 0) {
- excludesPattern = new HashSet(Arrays.asList(exclusions.split("\\s*,\\s*")));
+ {
+ String exclusions = config.getInitParameter(PARAM_NAME_EXCLUSIONS);
+ if (exclusions != null && exclusions.trim().length() != 0) {
+ excludesPattern = new HashSet(Arrays.asList(exclusions.split("\\s*,\\s*")));
+ }
+ }
+ {
+ String param = config.getInitParameter(PARAM_NAME_SESSION_STAT_ENABLE);
+ if (param != null && param.trim().length() != 0) {
+ param = param.trim();
+ if ("true".equals(param)) {
+ this.sessionStatEnable = true;
+ } else if ("false".equals(param)) {
+ this.sessionStatEnable = false;
+ } else {
+ LOG.error("WebStatFilter Parameter '" + PARAM_NAME_SESSION_STAT_ENABLE + "' config error");
+ }
+ }
+ }
+ {
+ String param = config.getInitParameter(PARAM_NAME_SESSION_STAT_MAX_COUNT);
+ if (param != null && param.trim().length() != 0) {
+ param = param.trim();
+ try {
+ this.sessionStatMaxCount = Integer.parseInt(param);
+ } catch (NumberFormatException e) {
+ LOG.error("WebStatFilter Parameter '" + PARAM_NAME_SESSION_STAT_ENABLE + "' config error", e);
+ }
+ }
}
- config.getServletContext().getContextPath();
StatFilterContext.getInstance().addContextListener(statFilterContextListener);
this.contextPath = DruidWebUtils.getContextPath(config.getServletContext());
- webAppStat = new WebAppStat(contextPath);
+ webAppStat = new WebAppStat(contextPath, this.sessionStatMaxCount);
WebAppStatManager.getInstance().addWebAppStatSet(webAppStat);
}
@@ -186,6 +224,30 @@ public class WebStatFilter implements Filter {
}
}
+ public boolean isSessionStatEnable() {
+ return sessionStatEnable;
+ }
+
+ public void setSessionStatEnable(boolean sessionStatEnable) {
+ this.sessionStatEnable = sessionStatEnable;
+ }
+
+ public WebAppStat getWebAppStat() {
+ return webAppStat;
+ }
+
+ public String getContextPath() {
+ return contextPath;
+ }
+
+ public int getSessionStatMaxCount() {
+ return sessionStatMaxCount;
+ }
+
+ public WebStatFilterContextListener getStatFilterContextListener() {
+ return statFilterContextListener;
+ }
+
class WebStatFilterContextListener extends StatFilterContextListenerAdapter {
@Override
diff --git a/src/main/java/com/alibaba/druid/support/http/stat/WebAppStat.java b/src/main/java/com/alibaba/druid/support/http/stat/WebAppStat.java
index f9d9611525..fc705ce184 100644
--- a/src/main/java/com/alibaba/druid/support/http/stat/WebAppStat.java
+++ b/src/main/java/com/alibaba/druid/support/http/stat/WebAppStat.java
@@ -8,44 +8,56 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
+import com.alibaba.druid.util.LRUCache;
public class WebAppStat {
- private final static Log LOG = LogFactory.getLog(WebAppStat.class);
+ private final static Log LOG = LogFactory.getLog(WebAppStat.class);
- public final static int DEFAULT_MAX_STAT_URI_COUNT = 1000;
- public final static int DEFAULT_MAX_STAT_SESSION_COUNT = 1000 * 100;
+ public final static int DEFAULT_MAX_STAT_URI_COUNT = 1000;
+ public final static int DEFAULT_MAX_STAT_SESSION_COUNT = 1000 * 100;
- private volatile int maxStatUriCount = DEFAULT_MAX_STAT_URI_COUNT;
- private volatile int maxStatSessionCount = DEFAULT_MAX_STAT_SESSION_COUNT;
+ private volatile int maxStatUriCount = DEFAULT_MAX_STAT_URI_COUNT;
+ private volatile int maxStatSessionCount = DEFAULT_MAX_STAT_SESSION_COUNT;
- private final AtomicInteger runningCount = new AtomicInteger();
- private final AtomicInteger concurrentMax = new AtomicInteger();
- private final AtomicLong requestCount = new AtomicLong(0);
+ private final AtomicInteger runningCount = new AtomicInteger();
+ private final AtomicInteger concurrentMax = new AtomicInteger();
+ private final AtomicLong requestCount = new AtomicLong(0);
- private final static ThreadLocal currentLocal = new ThreadLocal();
+ private final static ThreadLocal currentLocal = new ThreadLocal();
- private final ConcurrentMap uriStatMap = new ConcurrentHashMap();
- private final ConcurrentMap sessionStatMap = new ConcurrentHashMap();
+ private final ConcurrentMap uriStatMap = new ConcurrentHashMap();
+ private final Map sessionStatMap;
- private final AtomicLong uriStatMapFullCount = new AtomicLong();
- private final AtomicLong uriSessionMapFullCount = new AtomicLong();
+ private final ReadWriteLock sessionStatLock = new ReentrantReadWriteLock();
- private String contextPath;
+ private final AtomicLong uriStatMapFullCount = new AtomicLong();
+ private final AtomicLong uriSessionMapFullCount = new AtomicLong();
+
+ private String contextPath;
public static WebAppStat current() {
return currentLocal.get();
}
public WebAppStat(){
-
+ this(null);
}
public WebAppStat(String contextPath){
+ this(contextPath, DEFAULT_MAX_STAT_SESSION_COUNT);
+ }
+
+ public WebAppStat(String contextPath, int maxStatSessionCount){
this.contextPath = contextPath;
+ this.maxStatSessionCount = maxStatSessionCount;
+
+ sessionStatMap = new LRUCache(maxStatSessionCount);
}
public String getContextPath() {
@@ -101,26 +113,49 @@ public class WebAppStat {
}
public WebSessionStat getSessionStat(String sessionId) {
- if (sessionStatMap.size() >= this.getMaxStatSessionCount()) {
- long fullCount = uriSessionMapFullCount.getAndIncrement();
+ return getSessionStat(sessionId, false);
+ }
- if (fullCount == 0) {
- LOG.error("sessionStatMap is full");
+ public WebSessionStat getSessionStat(String sessionId, boolean create) {
+ sessionStatLock.readLock().lock();
+ try {
+ WebSessionStat uriStat = sessionStatMap.get(sessionId);
+
+ if (uriStat != null) {
+ return uriStat;
}
+ } finally {
+ sessionStatLock.readLock().unlock();
+ }
+ if (!create) {
return null;
}
- WebSessionStat uriStat = sessionStatMap.get(sessionId);
+ sessionStatLock.writeLock().lock();
+ try {
+ WebSessionStat uriStat = sessionStatMap.get(sessionId);
- if (uriStat == null) {
- WebSessionStat newStat = new WebSessionStat(sessionId);
-
- sessionStatMap.putIfAbsent(sessionId, newStat);
- uriStat = sessionStatMap.get(sessionId);
+ if (uriStat == null) {
+ if (sessionStatMap.size() >= this.getMaxStatSessionCount()) {
+ long fullCount = uriSessionMapFullCount.getAndIncrement();
+
+ if (fullCount == 0) {
+ LOG.error("sessionStatMap is full");
+ }
+ }
+
+ WebSessionStat newStat = new WebSessionStat(sessionId);
+
+ sessionStatMap.put(sessionId, newStat);
+
+ return newStat;
+ }
+
+ return uriStat;
+ } finally {
+ sessionStatLock.writeLock().unlock();
}
-
- return uriStat;
}
public void afterInvoke(long nanoSpan) {
@@ -193,19 +228,19 @@ public class WebAppStat {
}
return uriStatDataList;
}
-
+
public List