摘要:下面是源代碼片段的調用鏈是這樣的里有一個線程實例,這個線程會每隔的時間調用,這個方法調用,這個方法調用,這個方法調用,在這里清理掉已經過期的。下面是源代碼片段的值會作為新的默認的值實際上用戶在到后修改這個值。
我有一個項目需要模擬HttpSession,在參考Tomcat的HttpSession管理時有一點心得,在這里記錄一下。
先說說這幾個關鍵類:
org.apache.catalina.session.StandardManager: 管理Session的類
org.apache.catalina.session.StandardSession: HttpSession的實現
org.apache.catalina.connector.Request: HttpServletRequest的實現
StandardManager下面介紹一下和Session相關的幾個關鍵屬性,以及方法
processExpiresFrequency每隔多少次StandardManager.backgroundProcess做一次session清理,數字越小越頻繁,默認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的調用鏈是這樣的:
ContainerBase里有一個ContainerBackgroundProcessor線程實例,
這個線程會每隔ContainerBase.backgroundProcessorDelay的時間調用-->
ContainerBase.processChildren,這個方法調用-->
ContainerBase.backgroundProcess,這個方法調用-->
StandardManager.backgroundProcess,這個方法調用-->
StandardManager.processExpires,在這里清理掉已經過期的Session。
maxInactiveInterval一個session不被訪問的時間間隔,默認30分鐘(1800秒)。
下面是源代碼片段:
/** * The default maximum inactive interval for Sessions created by * this Manager. */ protected int maxInactiveInterval = 30 * 60;
StandardManager.maxInactiveInterval的值會作為新Session的默認maxInactiveInterval的值
(實際上用戶在get到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); // ... }StandardSession access()
StandardSession.access方法是用來設置這個Session被訪問的時間的,何時被調用會在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方法是用來設置這個Session訪問結束的時間的,何時被調用會在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方法是很關鍵的,這個方法會用來判斷這個Session是否還處于有效狀態。
代碼片段:
/**
* 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是否過期前,是否要先判斷一下這個session是否還在使用中(用accessCount判斷)
如果是,那么這個session是不會過期的。
如果不是,那么這個session就會被“粗暴”地過期。
LAST_ACCESS_AT_START,是兩種判斷session過期方式的開關
如果為true,會根據getSession的時間判斷是否過期了。access()和endAccess()之間的時間是不算進去的。
如果為false,則根據session結束訪問的時間判斷是否過期了。access()和endAccess()之間的時間是算進去的。
Request doGetSession()這個方法是tomcat獲得session的地方,從下面的代碼判斷里可以看到,它會調用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) { // 在這里調用了access session.access(); return (session); } } // ... }recycle()
這個當一個請求處理完畢后,CoyoteAdapter會調用Request.recycle()方法,
而這個方法會調用StandardSession.endAccess()方法(也就是告訴Session,你的這次訪問結束了)
/** * 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); } } // ... }
所以,當用戶調用HttpSession.getSession()方法時,發生了這些事情:
Request.doGetSession()
StandardSession.access()
返回給用戶Session
用戶在Servlet里處理完請求
Request.recycle()
StandardSession.endAccess()
陷阱從上面的流程可以看出Tomcat假設在Request的生命周期結束之后便不會有人再去訪問Session了。
但是如果我們在處理Request的Thread A里另起一個Thread B,并且在Thread B里訪問Session時會怎樣呢?
你可能已經猜到,可能會訪問到一個已經過期的Session。下面是一個小小的測試代碼:
https://gist.github.com/chanjarster/e1793251477cbabfbe92
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64926.html
摘要:前言對的管理一直有了解,但是一直沒有實際操作一遍,本文從最簡單的安裝啟動開始,通過實例的方式循序漸進的介紹了幾種管理的方式。 前言 Nginx+Tomcat對Session的管理一直有了解,但是一直沒有實際操作一遍,本文從最簡單的安裝啟動開始,通過實例的方式循序漸進的介紹了幾種管理session的方式。 nginx安裝配置 1.安裝nginx [root@localhost ~]# y...
閱讀 2986·2020-01-08 12:17
閱讀 1991·2019-08-30 15:54
閱讀 1152·2019-08-30 15:52
閱讀 2033·2019-08-29 17:18
閱讀 1042·2019-08-29 15:34
閱讀 2460·2019-08-27 10:58
閱讀 1861·2019-08-26 12:24
閱讀 368·2019-08-23 18:23