Tomcat如何監(jiān)控并刪除超時Session詳解
偶然發(fā)現(xiàn)Tomcat會話時間的半小時,并不是說會話創(chuàng)建后,只有半小時的有效使用時間,而是說會話空閑半小時后,會被刪除。索性就翻了一下源碼。做了一番整理。
注:空閑時間,指的是同一個會話兩次請求之間的間隔時間
Session相關(guān)類圖
- HttpSession就是大家Servlet層可以直接使用的Session.
- Session是Tomcat內(nèi)部使用的接口,可以做一些內(nèi)部調(diào)用
- StandardSession是標(biāo)準的HttpSession實現(xiàn),同時它也實現(xiàn)了Session接口,用于Tomcat內(nèi)部管理
- StandardSessionFacade,類名已經(jīng)指明它就是一個“門面類”,它內(nèi)部會引用一個StandardSession的對象,但對外只提供HttpSession規(guī)定的方法。
Manager相關(guān)類圖
StandardManager與PersitentManager都是Manager的實現(xiàn),但是它們在存儲Session對象的方式上有所不同。
StandarManager
1.Tomcat運行時,把Session存儲在內(nèi)存中
2.Tomcat關(guān)閉時(注意是正常的關(guān)閉操作,而非突然崩潰),會把Session寫入到磁盤中,等到Tomcat重啟后再把Session加載進來
PersistentManager
1.總是把Session存儲在磁盤中。
Manager與Context的關(guān)系
在Tomcat中,一個Context就是部署到Tomcat中的一個應(yīng)用(Webapp)。每一個Context都有一個單獨的Manager對象來管理這個應(yīng)用的會話信息。
Manager如何存儲Session
Manager對象會使用一個Map來存儲Session對象
- Key => SessionId
- Value => Session Object
/** * The set of currently active Sessions for this Manager, keyed by * session identifier. */ protected Map<String, Session> sessions = new ConcurrentHashMap<>();
當(dāng)一個請求到達Context的時候,如果它帶有JSESSIONID的Cookie,Manager就能依此找到關(guān)聯(lián)的Session對象,放入到Request對象中。
Manager的定期檢查
Manager接口有一個backgroundProcess()方法,顧名思義就是后臺處理。
/** * This method will be invoked by the context/container on a periodic * basis and allows the manager to implement * a method that executes periodic tasks, such as expiring sessions etc. */ public void backgroundProcess();
注:Container接口也有這個方法,這個方法一般在容器啟動(start)的時候,開啟一個額外的線程來執(zhí)行這個backgroundProcess方法。其中Context的這個方法啟動后,會執(zhí)行Loader和Manager的backgroundProcess方法。
我們來看看這個方法都做了些什么?
/** * {@inheritDoc} * <p> * Direct call to {@link #processExpires()} */ @Override public void backgroundProcess() { count = (count + 1) % processExpiresFrequency; if (count == 0) //如果達到檢查頻率則開始檢查 processExpires(); } /** * Invalidate all sessions that have expired. */ public void processExpires() { long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); //獲取所有session對象 int expireHere = 0 ; //過期session的數(shù)量,不要被這個變量名騙了 if(log.isDebugEnabled()) log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { if (sessions[i]!=null && !sessions[i].isValid()) { expireHere++; } } long timeEnd = System.currentTimeMillis(); if(log.isDebugEnabled()) //打印記錄 log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); processingTime += ( timeEnd - timeNow ); }
很多人看到這里,可能會有跟我一樣的疑惑,即這里面根本就沒有使Session過期失效的操作,好像只做了狀態(tài)檢查。不過后來看到了Session的isValid方法的實現(xiàn)就都明白了。
/** * Return the <code>isValid</code> 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; } //關(guān)鍵所在 //如果有設(shè)置最大空閑時間 //就獲取此Session的空閑時間進行判斷 //如果已超時,則執(zhí)行expire操作 if (maxInactiveInterval > 0) { int timeIdle = (int) (getIdleTimeInternal() / 1000L); if (timeIdle >= maxInactiveInterval) { expire(true); } } return this.isValid; }
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對本站的支持。
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。