摘要:下面是源代碼片段的調(diào)用鏈?zhǔn)沁@樣的里有一個(gè)線程實(shí)例,這個(gè)線程會(huì)每隔的時(shí)間調(diào)用,這個(gè)方法調(diào)用,這個(gè)方法調(diào)用,這個(gè)方法調(diào)用,在這里清理掉已經(jīng)過(guò)期的。下面是源代碼片段的值會(huì)作為新的默認(rèn)的值實(shí)際上用戶在到后修改這個(gè)值。
我有一個(gè)項(xiàng)目需要模擬HttpSession,在參考Tomcat的HttpSession管理時(shí)有一點(diǎn)心得,在這里記錄一下。
先說(shuō)說(shuō)這幾個(gè)關(guān)鍵類(lèi):
org.apache.catalina.session.StandardManager: 管理Session的類(lèi)
org.apache.catalina.session.StandardSession: HttpSession的實(shí)現(xiàn)
org.apache.catalina.connector.Request: HttpServletRequest的實(shí)現(xiàn)
StandardManager下面介紹一下和Session相關(guān)的幾個(gè)關(guān)鍵屬性,以及方法
processExpiresFrequency每隔多少次StandardManager.backgroundProcess做一次session清理,數(shù)字越小越頻繁,默認(rèn)6次。
下面是源代碼片段:
/** * Frequency of the session expiration, and related manager operations. * Manager operations will be done once for the specified amount of * backgrondProcess calls (ie, the lower the amount, the most often the * checks will occur). */ protected int processExpiresFrequency = 6;
StandardManager.backgroundProcess的調(diào)用鏈?zhǔn)沁@樣的:
ContainerBase里有一個(gè)ContainerBackgroundProcessor線程實(shí)例,
這個(gè)線程會(huì)每隔ContainerBase.backgroundProcessorDelay的時(shí)間調(diào)用-->
ContainerBase.processChildren,這個(gè)方法調(diào)用-->
ContainerBase.backgroundProcess,這個(gè)方法調(diào)用-->
StandardManager.backgroundProcess,這個(gè)方法調(diào)用-->
StandardManager.processExpires,在這里清理掉已經(jīng)過(guò)期的Session。
maxInactiveInterval一個(gè)session不被訪問(wèn)的時(shí)間間隔,默認(rèn)30分鐘(1800秒)。
下面是源代碼片段:
/** * The default maximum inactive interval for Sessions created by * this Manager. */ protected int maxInactiveInterval = 30 * 60;
StandardManager.maxInactiveInterval的值會(huì)作為新Session的默認(rèn)maxInactiveInterval的值
(實(shí)際上用戶在get到session后修改這個(gè)值)。
下面是代碼片段:
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); // ... }StandardSession access()
StandardSession.access方法是用來(lái)設(shè)置這個(gè)Session被訪問(wèn)的時(shí)間的,何時(shí)被調(diào)用會(huì)在Request里講。
下面是代碼片段:
/** * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular * session, even if the application does not reference it. */ @Override public void access() { this.thisAccessedTime = System.currentTimeMillis(); if (ACTIVITY_CHECK) { accessCount.incrementAndGet(); } }endAccess()
StandardSession.endAccess方法是用來(lái)設(shè)置這個(gè)Session訪問(wèn)結(jié)束的時(shí)間的,何時(shí)被調(diào)用會(huì)在Request里講。
/** * End the access. */ @Override public void endAccess() { isNew = false; /** * The servlet spec mandates to ignore request handling time * in lastAccessedTime. */ if (LAST_ACCESS_AT_START) { this.lastAccessedTime = this.thisAccessedTime; this.thisAccessedTime = System.currentTimeMillis(); } else { this.thisAccessedTime = System.currentTimeMillis(); this.lastAccessedTime = this.thisAccessedTime; } if (ACTIVITY_CHECK) { accessCount.decrementAndGet(); } }isValid()
StandardSession.isValid方法是很關(guān)鍵的,這個(gè)方法會(huì)用來(lái)判斷這個(gè)Session是否還處于有效狀態(tài)。
代碼片段:
/**
* Return the isValid
flag for this session.
*/
@Override
public boolean isValid() {
if (!this.isValid) {
return false;
}
if (this.expiring) {
return true;
}
if (ACTIVITY_CHECK && accessCount.get() > 0) {
return true;
}
if (maxInactiveInterval > 0) {
long timeNow = System.currentTimeMillis();
int timeIdle;
if (LAST_ACCESS_AT_START) {
timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L);
} else {
timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
}
if (timeIdle >= maxInactiveInterval) {
expire(true);
}
}
return this.isValid;
}
ACTIVITY_CHECK,的意思是判斷session是否過(guò)期前,是否要先判斷一下這個(gè)session是否還在使用中(用accessCount判斷)
如果是,那么這個(gè)session是不會(huì)過(guò)期的。
如果不是,那么這個(gè)session就會(huì)被“粗暴”地過(guò)期。
LAST_ACCESS_AT_START,是兩種判斷session過(guò)期方式的開(kāi)關(guān)
如果為true,會(huì)根據(jù)getSession的時(shí)間判斷是否過(guò)期了。access()和endAccess()之間的時(shí)間是不算進(jìn)去的。
如果為false,則根據(jù)session結(jié)束訪問(wèn)的時(shí)間判斷是否過(guò)期了。access()和endAccess()之間的時(shí)間是算進(jìn)去的。
Request doGetSession()這個(gè)方法是tomcat獲得session的地方,從下面的代碼判斷里可以看到,它會(huì)調(diào)用StandardSession.access()方法:
protected Session doGetSession(boolean create) { // There cannot be a session if no context has been assigned yet if (context == null) { return (null); } // Return the current session if it exists and is valid if ((session != null) && !session.isValid()) { session = null; } if (session != null) { return (session); } // 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) { // 在這里調(diào)用了access session.access(); return (session); } } // ... }recycle()
這個(gè)當(dāng)一個(gè)請(qǐng)求處理完畢后,CoyoteAdapter會(huì)調(diào)用Request.recycle()方法,
而這個(gè)方法會(huì)調(diào)用StandardSession.endAccess()方法(也就是告訴Session,你的這次訪問(wèn)結(jié)束了)
/** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { // ... if (session != null) { try { session.endAccess(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t); } } // ... }
所以,當(dāng)用戶調(diào)用HttpSession.getSession()方法時(shí),發(fā)生了這些事情:
Request.doGetSession()
StandardSession.access()
返回給用戶Session
用戶在Servlet里處理完請(qǐng)求
Request.recycle()
StandardSession.endAccess()
陷阱從上面的流程可以看出Tomcat假設(shè)在Request的生命周期結(jié)束之后便不會(huì)有人再去訪問(wèn)Session了。
但是如果我們?cè)谔幚鞷equest的Thread A里另起一個(gè)Thread B,并且在Thread B里訪問(wèn)Session時(shí)會(huì)怎樣呢?
你可能已經(jīng)猜到,可能會(huì)訪問(wèn)到一個(gè)已經(jīng)過(guò)期的Session。下面是一個(gè)小小的測(cè)試代碼:
https://gist.github.com/chanjarster/e1793251477cbabfbe92
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64926.html
摘要:前言對(duì)的管理一直有了解,但是一直沒(méi)有實(shí)際操作一遍,本文從最簡(jiǎn)單的安裝啟動(dòng)開(kāi)始,通過(guò)實(shí)例的方式循序漸進(jìn)的介紹了幾種管理的方式。 前言 Nginx+Tomcat對(duì)Session的管理一直有了解,但是一直沒(méi)有實(shí)際操作一遍,本文從最簡(jiǎn)單的安裝啟動(dòng)開(kāi)始,通過(guò)實(shí)例的方式循序漸進(jìn)的介紹了幾種管理session的方式。 nginx安裝配置 1.安裝nginx [root@localhost ~]# y...
閱讀 3092·2020-01-08 12:17
閱讀 2018·2019-08-30 15:54
閱讀 1171·2019-08-30 15:52
閱讀 2061·2019-08-29 17:18
閱讀 1068·2019-08-29 15:34
閱讀 2482·2019-08-27 10:58
閱讀 1890·2019-08-26 12:24
閱讀 403·2019-08-23 18:23