tomcat StandardSession
Tomcat中Session的实现还是比较清晰的,先看类图:其中HttpSession是Servlet Api,从类图看出来,这里使用了facade模式,StandardSessionFacade为一个门面,而 HttpSession的真正的实现类为StandardSession,它还实现了一个在tomcat内部使用的Session接口,这里讲的都是单台Tomcat的Session,tomcat集群是另外一套的代码。
Manager接口的实现是Session的管理者,保存着这台tomcat中所有的Session.Manager在Context启动的时候被创建,被启动.
在Servlet api中HttpServletRequest的getSession()方法最后面定位到的就是ManagerBase的createSession()方法,当然在这个以前,会查看是否已经存在session,有的话就直接返回了, 所以HttpServletRequest的getSession(boolean create)方法可以指定是否在没有找到session的情况下创建session。
public Session createSession(String sessionId) {
// Recycle or create a Session instance
Session 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);
if (sessionId == null) {
sessionId = generateSessionId();
// FIXME WHy we need no duplication check?
/*
synchronized (sessions) {
while (sessions.get(sessionId) != null) { // Guarantee
// uniqueness
duplicates++;
sessionId = generateSessionId();
}
}
*/
// FIXME: Code to be used in case route replacement is needed
/*
} else {
String jvmRoute = getJvmRoute();
if (getJvmRoute() != null) {
String requestJvmRoute = null;
int index = sessionId.indexOf(".");
if (index > 0) {
requestJvmRoute = sessionId
.substring(index + 1, sessionId.length());
}
if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) {
sessionId = sessionId.substring(0, index) + "." + jvmRoute;
}
}
*/
}
session.setId(sessionId);
sessionCounter++;
return (session);
}
首先创建一个空的Session,然后是设置各种属性,比较重要的是在sessionId没有传入的情况下,生成一个唯一的sessionId的过程。
protected synchronized String generateSessionId() {
byte random[] = new byte;
String jvmRoute = getJvmRoute();
String result = null;
// Render the result as a String of hexadecimal digits
StringBuffer buffer = new StringBuffer();
do {
int resultLenBytes = 0;
if (result != null) {
buffer = new StringBuffer();
duplicates++;
}
while (resultLenBytes < this.sessionIdLength) {
getRandomBytes(random);
random = getDigest().digest(random);
for (int j = 0;
j < random.length && resultLenBytes < this.sessionIdLength;
j++) {
byte b1 = (byte) ((random & 0xf0) >> 4);
byte b2 = (byte) (random & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
if (jvmRoute != null) {
buffer.append('.').append(jvmRoute);
}
result = buffer.toString();
} while (sessions.containsKey(result));
return (result);
}
在单台tomcat的情况下,jvmRoute是null的,这个随机数产生主要是要平衡,每次要求产生都尽可能的不一样,首先是new一个byte的数组,然后先去文件里面读取随机数,如果不行的话,需要产生一个种子来初始化一个随机数生成器然后生成随机数,之后进行MD5的计算,当然还是要判断一下这个id是不是已经存在了.
StandardManager还有很有意思的方法,在stop()方法中会调用unload()方法,这个方法把session的数据保存到文件中,当然也可以从文件中读书,这个文件存在于tomcat work对应项目目录下面的SESSIONS.ser文件中.
StandardSession中还有几个方法是对应Session Listener的,这些Session Listener是在Servlet Api中的,这样子的话,我们在外面实现这些类的时候,可以对应在Session发生变化的时候,tomcat有个回调我们类的机会
这些listener有:
HttpSessionListener 在session创建和销毁时用(StandardSession.setId(),StandardSession.expire())
HttpSessionActivationListener 在session钝化和反钝化时用(StandardSession.doUnload(),StandardSession.doload())
HttpSessionAttributeListener 在session的attributes属性发生变化时
页:
[1]