在難也要學(xué)完《深入分析的Java Web》的深入理解Session與Cookie,斷斷續(xù)續(xù)花了三四天的時(shí)間在學(xué)習(xí)這塊內(nèi)容,好難啊,但還是得逼自己學(xué)完,不想一直掉坑里
記錄一下學(xué)習(xí)內(nèi)容,這樣哪天忘記了又能重新拾起來
(一)淺入部分:方法使用介紹
1.Session創(chuàng)建的時(shí)間:客戶端第一次請(qǐng)求服務(wù)器的時(shí)候創(chuàng)建的。
通過request.getSession()可以獲得對(duì)應(yīng)的session對(duì)象(返回類型為HttpSession),不存在將返回null。調(diào)用request.getSession(true),如果該客戶的session不存在,將先創(chuàng)建session對(duì)象,在返回session。
測(cè)試代碼:SessionTest.java
public class SessionTest extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String id = session.getId();
System.out.println("session_id: " + id);
}
}
運(yùn)行結(jié)果:
session_id: BE37D76B19597F991999F482A0A6F9BD
說明在客戶端第一次請(qǐng)求時(shí)就創(chuàng)建了session對(duì)象,并且這個(gè)過程對(duì)我們來說是透明的。
注:獲取session時(shí)只需調(diào)用getSession()方法就可以了,不需要指定是哪個(gè)客戶端的session。session的機(jī)制決定了當(dāng)前客戶只會(huì)獲得自己的session,而不會(huì)獲得別人的session。各客戶的session互相獨(dú)立、互不可見
2.session的生命周期
tomcat8中默認(rèn)session的生命周期為30min
<!-- ==================== Default Session Configuration ================= -->
<!-- You can set the default session timeout (in minutes) for all newly -->
<!-- created sessions by modifying the value below. -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
session的生命周期沒有cookie長(zhǎng)是有原因的,cookie保存在瀏覽器中一般是永久的。session就不一樣了,為了獲得更高的緩存速度,服務(wù)器一般把session保存在內(nèi)存中,但是,如果網(wǎng)站是高并發(fā)的,并且session保存的內(nèi)容很多,就會(huì)造成內(nèi)存溢出,所以需要定期清除那些不常用的session,通過設(shè)置一個(gè)時(shí)間,時(shí)間不可以太長(zhǎng),超時(shí)清理,緩減內(nèi)存壓力。如果自己需要更改sessiond的生命周期,有兩種方式可以修改
1)tomcat web.xml文件中進(jìn)行修改
2)調(diào)用setMaxInactiveInterval(int i)方法進(jìn)行修改
注意web.xml中時(shí)間的單位為小時(shí),setMaxInactiveInterval(int i)方法中時(shí)間的單位為秒
3.session對(duì)瀏覽器的要求
session需要依賴cookie,服務(wù)器生成session時(shí)會(huì)生成一個(gè)name為jsessionid的cookie,值為session的id(即HttpSession.getId()的返回值),session通過cookie來識(shí)別是否為同一個(gè)用戶。服務(wù)器自動(dòng)生成的cookie,maxAge屬性一般為-1,僅在當(dāng)前瀏覽器內(nèi)的當(dāng)前窗口有效,關(guān)閉瀏覽器就會(huì)失效。如果瀏覽器禁用cookie或不支持cookie,就需要使用url地址重寫 。
url地址重寫原理:將該用戶的session的id信息重寫到url地址中。服務(wù)器能夠解析重寫后的url獲取session的id。這樣就可以不需要使用cookie記錄session的id了。
測(cè)試代碼:SessionTest.java
public class SessionTest extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("進(jìn)入SessionTest方法體內(nèi)");
HttpSession session = request.getSession();
String id = session.getId();
System.out.println("session_id: " + id);
Cookie[] cookies = request.getCookies();
System.out.println("size: " + cookies.length);
if (cookies.length != 0) {
for (Cookie c : cookies) {
System.out.println("name: " + c.getName() + " value: " + c.getValue());
}
}
// response.sendRedirect("/cookie_message");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
運(yùn)行結(jié)果:
進(jìn)入SessionTest方法體內(nèi)
session_id: 5748CB766C7130F80F259E72A5637920
進(jìn)入SessionTest方法體內(nèi)
session_id: 5748CB766C7130F80F259E72A5637920
size: 1
name: JSESSIONID value: 5748CB766C7130F80F259E72A5637920
先清理一下瀏覽器緩存,第一次進(jìn)入方法體時(shí)會(huì)報(bào)500空指針異常
報(bào)空指針異常的原因是此時(shí)request.getCookies()沒有結(jié)果,第二次繼續(xù)調(diào)用方法時(shí)才成功,從結(jié)果中看出確實(shí)生成一個(gè)name為JSESSIONID ,值為session id的cookie。
思考了一下出錯(cuò)原因:客戶端第一次請(qǐng)求服務(wù)器時(shí)生成一個(gè)session,同時(shí)生成了一個(gè)cookie,但這次生成的cookie要通過服務(wù)器的響應(yīng)以后才能返回給客戶端,所以第一次取不到想要的cookie。
禁用cookie后,因?yàn)樵趖omcat配置文件中禁用cookie沒有效果,直接禁用了瀏覽器

原來的程序運(yùn)行結(jié)果:
進(jìn)入SessionTest方法體內(nèi)
session_id: 39385CEDA231B7DDBC1A42C9BBB6EC92
進(jìn)入SessionTest方法體內(nèi)
session_id: 31E06944B9086767087BCF32E9A5D273
進(jìn)入SessionTest方法體內(nèi)
session_id: A796BD79458635C4C117198B09C9269C
進(jìn)入SessionTest方法體內(nèi)
session_id: 31D60D8791F88E7D28E567A085D3BFCC
一直報(bào)500空指針的錯(cuò)誤,也就是說明沒有cookie
那就使用url重寫
修改一下上面的代碼:
public class SessionTest extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("進(jìn)入SessionTest方法體內(nèi)");
HttpSession session = request.getSession();
String id = session.getId();
System.out.println("session_id: " + id);
response.sendRedirect(response.encodeRedirectURL("/cookie_message"));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
url地址欄變?yōu)榱耍?br>
http://localhost:8080/cookie_message;jsessionid=D4BCA30FE7A2E44D615DBFE04A4016A4
運(yùn)行結(jié)果:
進(jìn)入SessionTest方法體內(nèi)
session_id: D4BCA30FE7A2E44D615DBFE04A4016A4
說明url重定向成功了,這樣服務(wù)器可以通過url來獲得session id了
(二)深出部分:session底層是如何工作的
4.session工作機(jī)制
當(dāng)客戶端和服務(wù)器建立連接時(shí)會(huì)創(chuàng)建一個(gè)session,創(chuàng)建session對(duì)象的過程大致是這樣的:
1)解析url,url中是否有session id(一般可以解析的url是重寫后的url,像這樣,http://localhost:8080/cookie_message;jsessionid=D4BCA30FE7A2E44D615DBFE04A4016A4,id則為jsessionid)
2)如果瀏覽器是支持cookie的,則從cookie中拿到session id,并覆蓋之前的session id(即url重寫中的session id)
所以客戶端支持cookie,tomcat仍然會(huì)解析cookie中的session id,然后覆蓋url中的session id
3)根據(jù)session id在manager類的session容器中查找是否存在這個(gè)id的session對(duì)象
4)如果步驟3)中查找不到這個(gè)對(duì)象,則創(chuàng)建這個(gè)id的session對(duì)象
5)將這個(gè)session對(duì)象添加到session容器中
6)根據(jù)這個(gè)id新增一個(gè)cookie,并將這個(gè)cookie設(shè)置到http協(xié)議頭中
7)通過調(diào)用request.getSession()可以獲得該對(duì)象。它的底層是通過requestedSessionId從StandardManager(Manager的實(shí)現(xiàn)類)的sessions集合中(就是之前說的容器)獲取對(duì)應(yīng)客戶的HttpSession對(duì)象
5)管理session對(duì)象的StandardManager類介紹
StandardManager類負(fù)責(zé)Servlet容器中所有session對(duì)象生命周期的管理。當(dāng)tomcat重啟或關(guān)閉時(shí),StandardManager通過序列化(調(diào)用unload方法)將沒有過期的session對(duì)象持久化到SESSIONS.ser文件中,當(dāng)tomcat重啟時(shí),即StandardManager初始化時(shí),會(huì)重新讀取這個(gè)文件,解析出所有的session對(duì)象保存到StandardManager的session集合中。注意:在重啟讀取SESSIONS.ser文件時(shí),會(huì)在一次進(jìn)行檢查session是否過期,過期就不在加載到sessions集合中了 。不正常的關(guān)閉tomcat服務(wù)器也有可能不會(huì)對(duì)session進(jìn)行持久化,因?yàn)檎{(diào)用不到unload方法
SESSIONS.ser這個(gè)文件有點(diǎn)難找,最后選擇以搜索的方式查找到了這類文件

6)session過期清理
檢查session是否過期是tomcat中的一個(gè)后臺(tái)線程完成的(backgroundProcess()方法),如果過期了,則將設(shè)置Session.expire(true),否則保留session。過期了的session對(duì)象不是立刻就被清理的,tomcat使用一個(gè)1分鐘的定時(shí)任務(wù)定時(shí)清除當(dāng)前超時(shí)session對(duì)象,所以清除超時(shí)的session對(duì)象有一個(gè)小于1分鐘的延時(shí),在處理過期問題上,redis清理過期鍵的機(jī)制和它類似。如果此時(shí)expire=true,但是定時(shí)任務(wù)時(shí)間沒有到,客戶端發(fā)送request.getSession()請(qǐng)求,則這個(gè)session對(duì)象將會(huì)被立刻清理掉,不會(huì)等定時(shí)任務(wù)來清理,并創(chuàng)建一個(gè)新的session對(duì)象來響應(yīng)客戶端的請(qǐng)求
2017年最后一篇文章
繼續(xù)沉淀自己。酒越久越醇厚