服務器端實現原理
Session在服務器端具體是怎麼實現的呢?我們使用session的時候一般都是這麼使用的
request
getSession()或者request
getSession(true)
這個時候
服務器就檢查是不是已經存在對應的Session對象
見HttpRequestBase類
doGetSession(boolean create)方法
if ((session != null) && !session
isValid())
session = null;
if (session != null)
return (session
getSession())
// Return the requested session if it exists and is valid
Manager manager = null;
if (context != null)
manager = context
getManager()
if (manager == null)
return (null)
// Sessions are not supported
if (requestedSessionId != null) {
try {
session = manager
findSession(requestedSessionId)
} catch (IOException e) {
session = null;
}
if ((session != null) && !session
isValid())
session = null;
if (session != null) {
return (session
getSession())
}
}
requestSessionId從哪裡來呢?這個肯定是通過Session實現機制的cookie或URL重寫來設置的
見HttpProcessor類中的parseHeaders(SocketInputStream input)
for (int i =
; i < cookies
length; i++) {
if (cookies[i]
getName()
equals
(Globals
SESSION_COOKIE_NAME)) {
// Override anything requested in the URL
if (!request
isRequestedSessionIdFromCookie()) {
// Accept only the first session id cookie
request
setRequestedSessionId
(cookies[i]
getValue())
request
setRequestedSessionCookie(true)
request
setRequestedSessionURL(false)
}
}
}
或者HttpOrocessor類中的parseRequest(SocketInputStream input
OutputStream output)
// Parse any requested session ID out of the request URI
int semicolon = uri
indexOf(match)
//match 是
;jsessionid=
字符串
if (semicolon >=
) {
String rest = uri
substring(semicolon + match
length())
int semicolon
= rest
indexOf(
;
)
if (semicolon
>=
) {
request
setRequestedSessionId(rest
substring(
semicolon
))
rest = rest
substring(semicolon
)
} else {
request
setRequestedSessionId(rest)
rest =
;
}
request
setRequestedSessionURL(true)
uri = uri
substring(
semicolon) + rest;
if (debug >=
)
log(
Requested URL session id is
+
((HttpServletRequest) request
getRequest())
getRequestedSessionId())
} else {
request
setRequestedSessionId(null)
request
setRequestedSessionURL(false)
}
裡面的manager
findSession(requestSessionId)用於查找此會話ID對應的session對象
Tomcat實現是通過一個HashMap實現
見ManagerBase
java的findSession(String id)
if (id == null)
return (null)
synchronized (sessions) {
Session session = (Session) sessions
get(id)
return (session)
}
Session本身也是實現為一個HashMap
因為Session設計為存放key
value鍵值對
Tomcat裡面Session實現類是StandardSession
裡面一個attributes屬性
/**
* The collection of user data attributes associated with this Session
*/
private HashMap attributes = new HashMap()
所有會話信息的存取都是通過這個屬性來實現的
Session會話信息不會一直在服務器端保存
超過一定的時間期限就會被刪除
這個時間期限可以在 web
xml中進行設置
不設置的話會有一個默認值
Tomcat的默認值是
那麼服務器端是怎麼判斷會話過期的呢?原理服務器會啟動一個線程
一直查詢所有的Session對象
檢查不活動的時間是否超過設定值
如果超過就將其刪除
見StandardManager類
它實現了Runnable 接口
裡面的run方法如下
/**
* The background thread that checks for session timeouts and shutdown
*/
public void run() {
// Loop until the termination semaphore is set
while (!threadDone) {
threadSleep()
proces***pires()
}
}
/**
* Invalidate all sessions that have expired
*/
private void proces***pires() {
long timeNow = System
currentTimeMillis()
Session sessions[] = findSessions()
for (int i =
; i < sessions
length; i++) {
StandardSession session = (StandardSession) sessions[i];
if (!session
isValid())
continue;
int maxInactiveInterval = session
getMaxInactiveInterval()
if (maxInactiveInterval <
)
continue;
int timeIdle = // Truncate
do not round up
(int) ((timeNow
session
getLastUsedTime()) /
L)
if (timeIdle >= maxInactiveInterval) {
try {
expiredSessions++;
session
expire()
} catch (Throwable t) {
log(sm
getString(
standardManager
expireException
)
t)
}
}
}
}
Session 信息在create
expire等事情的時候都會觸發相應的Listener事件
從而可以對session信息進行監控
這些Listener只需要繼承HttpSessionListener
並配置在web
xml文件中
如下是一個監控在線會話數的Listerner:
import java
util
HashSet;
import javax
servlet
ServletContext;
import javax
servlet
http
HttpSession;
import javax
servlet
http
HttpSessionEvent;
import javax
servlet
http
HttpSessionListener;
public class MySessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event
getSession()
ServletContext application = session
getServletContext()
// 在application范圍由一個HashSet集保存所有的session
HashSet sessions = (HashSet) application
getAttribute(
sessions
)
if (sessions == null) {
sessions = new HashSet()
application
setAttribute(
sessions
sessions)
}
// 新創建的session均添加到HashSet集中
sessions
add(session)
// 可以在別處從application范圍中取出sessions集合
// 然後使用sessions
size()獲取當前活動的session數
即為
在線人數
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event
getSession()
ServletContext application = session
getServletContext()
HashSet sessions = (HashSet) application
getAttribute(
sessions
)
// 銷毀的session均從HashSet集中移除
sessions
remove(session)
}
}
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28703.html