issue #69 添加Session的支持

This commit is contained in:
Daniel Qian
2015-01-21 16:01:33 +08:00
parent 7ea6e3ec03
commit 4accbe6ec2
10 changed files with 205 additions and 35 deletions

View File

@@ -39,11 +39,9 @@ public interface InternalSession {
void access();
/**
* Set the <code>isNew</code> flag for this session.
*
* @param isNew The new value for the <code>isNew</code> flag
* End the access.
*/
void setNew(boolean isNew);
void endAccess();
/**
* Set the creation time for this session. This method is called by the

View File

@@ -4,6 +4,7 @@ import me.chanjar.weixin.common.util.res.StringManager;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class SessionImpl implements WxSession, InternalSession {
@@ -90,11 +91,6 @@ public class SessionImpl implements WxSession, InternalSession {
*/
protected volatile boolean isValid = false;
/**
* Flag indicating whether this session is new or not.
*/
protected boolean isNew = false;
/**
* We are currently processing a session expiration, so bypass
* certain IllegalStateException tests. NOTE: This value is not
@@ -123,11 +119,6 @@ public class SessionImpl implements WxSession, InternalSession {
*/
protected volatile long thisAccessedTime = creationTime;
/**
* The last accessed time for this Session.
*/
protected volatile long lastAccessedTime = creationTime;
/**
* The default maximum inactive interval for Sessions created by
* this Manager.
@@ -140,9 +131,15 @@ public class SessionImpl implements WxSession, InternalSession {
*/
protected transient InternalSessionFacade facade = null;
/**
* The access count for this session.
*/
protected transient AtomicInteger accessCount = null;
public SessionImpl(InternalSessionManager manager) {
this.manager = manager;
this.accessCount = new AtomicInteger();
}
@@ -176,7 +173,28 @@ public class SessionImpl implements WxSession, InternalSession {
@Override
public boolean isValid() {
return isValid;
if (!this.isValid) {
return false;
}
if (this.expiring) {
return true;
}
if (accessCount.get() > 0) {
return true;
}
if (maxInactiveInterval > 0) {
long timeNow = System.currentTimeMillis();
int timeIdle;
timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
if (timeIdle >= maxInactiveInterval) {
expire();
}
}
return this.isValid;
}
@Override
@@ -215,6 +233,8 @@ public class SessionImpl implements WxSession, InternalSession {
// Mark this session as "being expired"
expiring = true;
accessCount.set(0);
// Remove this session from our manager's active sessions
manager.remove(this, true);
@@ -238,23 +258,23 @@ public class SessionImpl implements WxSession, InternalSession {
public void access() {
this.thisAccessedTime = System.currentTimeMillis();
accessCount.incrementAndGet();
}
@Override
public void setNew(boolean isNew) {
public void endAccess() {
this.isNew = isNew;
this.thisAccessedTime = System.currentTimeMillis();
accessCount.decrementAndGet();
}
@Override
public void setCreationTime(long time) {
this.creationTime = time;
this.lastAccessedTime = time;
this.thisAccessedTime = time;
}

View File

@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class SessionManagerImpl implements WxSessionManager, InternalSessionManager {
@@ -104,6 +105,11 @@ public class SessionManagerImpl implements WxSessionManager, InternalSessionMana
*/
protected int processExpiresFrequency = 6;
/**
* 后台清理线程是否已经开启
*/
private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false);
@Override
public void remove(InternalSession session) {
remove(session, false);
@@ -155,7 +161,6 @@ public class SessionManagerImpl implements WxSessionManager, InternalSessionMana
InternalSession session = createEmptySession();
// Initialize the properties of the new session and return it
session.setNew(true);
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(this.maxInactiveInterval);
@@ -191,6 +196,26 @@ public class SessionManagerImpl implements WxSessionManager, InternalSessionMana
@Override
public void add(InternalSession session) {
// 当第一次有session创建的时候开启session清理线程
if (!backgroundProcessStarted.getAndSet(true)) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
// 每秒清理一次
Thread.sleep(1000l);
backgroundProcess();
} catch (InterruptedException e) {
log.error("SessionManagerImpl.backgroundProcess error", e);
}
}
}
});
t.setDaemon(true);
t.start();
}
sessions.put(session.getIdInternal(), session);
int size = getActiveSessions();
if( size > maxActive ) {

View File

@@ -2,9 +2,19 @@ package me.chanjar.weixin.common.session;
public interface WxSessionManager {
/**
* 获取某个sessionId对应的session,如果sessionId没有对应的session则新建一个并返回。
* @param sessionId
* @return
*/
public WxSession getSession(String sessionId);
/**
* 获取某个sessionId对应的session,如果sessionId没有对应的session若create为true则新建一个否则返回null。
* @param sessionId
* @param create
* @return
*/
public WxSession getSession(String sessionId, boolean create);

View File

@@ -2,6 +2,7 @@ package me.chanjar.weixin.common.util;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* <pre>
@@ -21,8 +22,16 @@ public class WxMsgIdMemoryDuplicateChecker implements WxMsgIdDuplicateChecker {
*/
private final Long clearPeriod;
/**
* 消息id->消息时间戳的map
*/
private final ConcurrentHashMap<Long, Long> msgId2Timestamp = new ConcurrentHashMap<Long, Long>();
/**
* 后台清理线程是否已经开启
*/
private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false);
/**
* WxMsgIdInMemoryDuplicateChecker构造函数
* <pre>
@@ -33,7 +42,6 @@ public class WxMsgIdMemoryDuplicateChecker implements WxMsgIdDuplicateChecker {
public WxMsgIdMemoryDuplicateChecker() {
this.timeToLive = 15 * 1000l;
this.clearPeriod = 5 * 1000l;
this.start();
}
/**
@@ -44,10 +52,12 @@ public class WxMsgIdMemoryDuplicateChecker implements WxMsgIdDuplicateChecker {
public WxMsgIdMemoryDuplicateChecker(Long timeToLive, Long clearPeriod) {
this.timeToLive = timeToLive;
this.clearPeriod = clearPeriod;
this.start();
}
private void start() {
protected void checkBackgroundProcessStarted() {
if (backgroundProcessStarted.getAndSet(true)) {
return;
}
Thread t = new Thread(new Runnable() {
@Override
public void run() {
@@ -72,6 +82,7 @@ public class WxMsgIdMemoryDuplicateChecker implements WxMsgIdDuplicateChecker {
@Override
public boolean isDuplicate(Long wxMsgId) {
checkBackgroundProcessStarted();
Long timestamp = msgId2Timestamp.putIfAbsent(wxMsgId, System.currentTimeMillis());
if (timestamp == null) {
// 第一次接收到这个消息