Tomcat源码分析(九)--Session管理
生活随笔
收集整理的這篇文章主要介紹了
Tomcat源码分析(九)--Session管理
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本系列轉(zhuǎn)載自?http://blog.csdn.net/haitao111313/article/category/1179996??parseConnection(socket);?? parseRequest(input,?output);//解析請(qǐng)求行,如果有jessionid,會(huì)在方法里面解析jessionid?? if?(!request.getRequest().getProtocol()?? ????.startsWith("HTTP/0"))?? ????parseHeaders(input);//解析請(qǐng)求頭部,如果有cookie字段,在方法里面會(huì)解析cookie,?? 下面看parseRequest方法里面是怎么解析jessionid的,這種解析方式是針對(duì)url重寫的:[java]?view plaincopyprint?parseRequest方法:?? int?semicolon?=?uri.indexOf(match);//match是“;JSESSIONID=”,即在請(qǐng)求行查找字段JSESSIONID?? ????????if?(semicolon?>=?0)?{???????????????????????????????????//如果有JSESSIONID字段,表示不是第一次訪問?? ????????????String?rest?=?uri.substring(semicolon?+?match.length());?? ????????????int?semicolon2?=?rest.indexOf(';');?? ????????????if?(semicolon2?>=?0)?{?? ????????????????request.setRequestedSessionId(rest.substring(0,?semicolon2));//設(shè)置sessionid?? ????????????????rest?=?rest.substring(semicolon2);?? ????????????}?else?{?? ????????????????request.setRequestedSessionId(rest);?? ????????????????rest?=?"";?? ????????????}?? ????????????request.setRequestedSessionURL(true);?? ????????????uri?=?uri.substring(0,?semicolon)?+?rest;?? ????????????if?(debug?>=?1)?? ????????????????log("?Requested?URL?session?id?is?"?+?? ????????????????????((HttpServletRequest)?request.getRequest())?? ????????????????????.getRequestedSessionId());?? ????????}?else?{???????????????????????????????//如果請(qǐng)求行沒有JSESSIONID字段,表示是第一次訪問。?? ????????????request.setRequestedSessionId(null);?? ????????????request.setRequestedSessionURL(false);?? ????????}??
代碼沒什么說的,看url有沒有JSESSIONID,有就設(shè)置request的sessionid,沒有就設(shè)置為null。有再看parseHeaders方法:[java]?view plaincopyprint?parseHeaders方法:?? .....?? ....else?if?(header.equals(DefaultHeaders.COOKIE_NAME))?{?//COOKIE_NAME的值是cookie?? ????????????????Cookie?cookies[]?=?RequestUtil.parseCookieHeader(value);?? ????????????????for?(int?i?=?0;?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());//設(shè)置sessionid?? ????????????????????????????request.setRequestedSessionCookie(true);?? ????????????????????????????request.setRequestedSessionURL(false);?? ????????????????????????????if?(debug?>=?1)?? ????????????????????????????????log("?Requested?cookie?session?id?is?"?+?? ????????????????????????????????????((HttpServletRequest)?request.getRequest())?? ????????????????????????????????????.getRequestedSessionId());?? ????????????????????????}?? ????????????????????}?? ????????????????????if?(debug?>=?1)?? ????????????????????????log("?Adding?cookie?"?+?cookies[i].getName()?+?"="?+?? ????????????????????????????cookies[i].getValue());?? ????????????????????request.addCookie(cookies[i]);?? ????????????????}?? ????????????}??? ? ? ? ?代碼主要就是從http請(qǐng)求頭部的字段cookie得到JSESSIONID并設(shè)置到reqeust的sessionid,沒有就不設(shè)置。這樣客戶端的JSESSIONID(cookie)就傳到tomcat,tomcat把JSESSIONID的值賦給request了。這個(gè)request在Tomcat的唯一性就標(biāo)識(shí)了。? ? ?我們知道,Session只對(duì)應(yīng)用有用,兩個(gè)應(yīng)用的Session一般不能共用,在Tomcat一個(gè)Context代表一個(gè)應(yīng)用,所以一個(gè)應(yīng)用應(yīng)該有一套自己的Session,Tomcat使用Manager來(lái)管理各個(gè)應(yīng)用的Session,Manager也是一個(gè)組件,跟Context是一一對(duì)應(yīng)的關(guān)系,怎么關(guān)聯(lián)的請(qǐng)參考Tomcat源碼分析(一)--服務(wù)啟動(dòng),方法類似。Manager的標(biāo)準(zhǔn)實(shí)現(xiàn)是StandardManager,由它統(tǒng)一管理Context的Session對(duì)象(標(biāo)準(zhǔn)實(shí)現(xiàn)是StandardSession),能夠猜想,StandardManager一定能夠創(chuàng)建Session對(duì)象和根據(jù)JSESSIONID從跟它關(guān)聯(lián)的應(yīng)用中查找Session對(duì)象。事實(shí)上StandardManager確實(shí)有這樣的方法,但是StandardManager本身沒有這兩個(gè)方法,它的父類ManagerBase有這兩個(gè)方法:[java]?view plaincopyprint?ManagerBase類的findSession和createSession()方法?? public?Session?findSession(String?id)?throws?IOException?{?? ????????if?(id?==?null)?? ????????????return?(null);?? ????????synchronized?(sessions)?{?? ????????????Session?session?=?(Session)?sessions.get(id);//根據(jù)sessionid(即<span?style="font-family:?Arial;?">JSESSIONID</span>)查找session對(duì)象。?? ????????????return?(session);?? ????????}?? ????}?? public?Session?createSession()?{?//創(chuàng)建session對(duì)象?? ????????//?Recycle?or?create?a?Session?instance?? ????????Session?session?=?null;?? ????????synchronized?(recycled)?{?? ????????????int?size?=?recycled.size();?? ????????????if?(size?>?0)?{?? ????????????????session?=?(Session)?recycled.get(size?-?1);?? ????????????????recycled.remove(size?-?1);?? ????????????}?? ????????}?? ????????if?(session?!=?null)?? ????????????session.setManager(this);?? ????????else?? ????????????session?=?new?StandardSession(this);?? ?? ????????//?Initialize?the?properties?of?the?new?session?and?return?it?? ????????session.setNew(true);?? ????????session.setValid(true);?? ????????session.setCreationTime(System.currentTimeMillis());?? ????????session.setMaxInactiveInterval(this.maxInactiveInterval);?? ????????String?sessionId?=?generateSessionId();//使用md5算法生成sessionId?? ????????String?jvmRoute?=?getJvmRoute();?? ????????//?@todo?Move?appending?of?jvmRoute?generateSessionId()????? ????????if?(jvmRoute?!=?null)?{?? ????????????sessionId?+=?'.'?+?jvmRoute;?? ????????????session.setId(sessionId);?? ????????}?? ????????session.setId(sessionId);?? ????????return?(session);?? ????}?? ? ? ? 以上是StandardManager的管理Session的兩個(gè)重要方法。這里有一個(gè)問題,Session是在什么時(shí)候生成的?仔細(xì)想想,我們編寫servlet的時(shí)候,如果需要用到Session,會(huì)使用request.getSession(),這個(gè)方法最后會(huì)調(diào)用到HttpRequestBase的getSession()方法,所以這里有個(gè)重要的點(diǎn):Session并不是在客戶端第一次訪問就會(huì)在服務(wù)器端生成,而是在服務(wù)器端(一般是servlet里)使用request調(diào)用getSession方法才生成的。但是默認(rèn)情況下,jsp頁(yè)面會(huì)調(diào)用request.getSession(),即jsp頁(yè)面的這個(gè)屬性<%@ page session="true" %>默認(rèn)是true的,編譯成servlet后會(huì)調(diào)用request.getSession()。所以只要訪問jsp頁(yè)面,一般是會(huì)在服務(wù)器端創(chuàng)建session的。但是在servlet里就需要顯示的調(diào)用getSession(),當(dāng)然是在要用session的情況。下面看這個(gè)getSession()方法:[java]?view plaincopyprint?HttpRequestBase.getSession()?? ???調(diào)用---------------》?? ????HttpRequestBase.getSession(boolean?create)?? ???????調(diào)用?----------------》?? ????????????HttpRequestBase.doGetSession(boolean?create){?? ??????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.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);//這里調(diào)用StandardManager的findSession方法查找是否存在Session對(duì)象?? ????????????}?catch?(IOException?e)?{?? ????????????????session?=?null;?? ????????????}?? ????????????if?((session?!=?null)?&&?!session.isValid())?? ????????????????session?=?null;?? ????????????if?(session?!=?null)?{?? ????????????????return?(session.getSession());?? ????????????}?? ????????}?? ?? ????????//?Create?a?new?session?if?requested?and?the?response?is?not?committed?? ????????if?(!create)?? ????????????return?(null);?? ????????if?((context?!=?null)?&&?(response?!=?null)?&&?? ????????????context.getCookies()?&&?? ????????????response.getResponse().isCommitted())?{?? ????????????throw?new?IllegalStateException?? ??????????????(sm.getString("httpRequestBase.createCommitted"));?? ????????}?? ?? ????????session?=?manager.createSession();//這里調(diào)用StandardManager的創(chuàng)建Session對(duì)象?? ????????if?(session?!=?null)?? ????????????return?(session.getSession());?? ????????else?? ????????????return?(null);?? }???????
? ? ? ? 至此,Tomcat的Session管理的大部分東西也寫的差不多了,這里沒有寫StandardManager和StandardSession兩個(gè)類以及他們的實(shí)現(xiàn)接口,還有繼承關(guān)系等,是因?yàn)橛X得這篇文章已經(jīng)夠長(zhǎng)了,而且他們跟跟其他標(biāo)準(zhǔn)組件也差不多,無(wú)非是實(shí)現(xiàn)的具體功能不一樣,比如StandardSession還有過期處理等,不過它們也跟其他組件有各種關(guān)系,比如StandardManager就跟Context容器是關(guān)聯(lián)的。有機(jī)會(huì)再細(xì)細(xì)的說Session管理器其他的東西(持久化和分布式)。
在明白Tomcat的Session機(jī)制之前,先要了解Session,Cookie,JSESSIONID這幾個(gè)概念。JSESSIONID是一個(gè)唯一標(biāo)識(shí)號(hào),用來(lái)標(biāo)識(shí)服務(wù)器端的Session,也用來(lái)標(biāo)識(shí)客戶端的Cookie,客戶端和服務(wù)器端通過這個(gè)JSESSIONID來(lái)一一對(duì)應(yīng)。這里需要說明的是Cookie已經(jīng)包含JSESSIONID了,可以理解為JSESSIONID是Cookie里的一個(gè)屬性。讓我假設(shè)一次客戶端連接來(lái)說明我對(duì)個(gè)這三個(gè)概念的理解:
? ? ?Http連接本身是無(wú)狀態(tài)的,即前一次發(fā)起的連接跟后一次沒有任何關(guān)系,是屬于兩次獨(dú)立的連接請(qǐng)求,但是互聯(lián)網(wǎng)訪問基本上都是需要有狀態(tài)的,即服務(wù)器需要知道兩次連接請(qǐng)求是不是同一個(gè)人訪問的。如你在瀏覽淘寶的時(shí)候,把一個(gè)東西加入購(gòu)物車,再點(diǎn)開另一個(gè)商品頁(yè)面的時(shí)候希望在這個(gè)頁(yè)面里面的購(gòu)物車還有上次添加進(jìn)購(gòu)物車的商品。也就是說淘寶服務(wù)器會(huì)知道這兩次訪問是同一個(gè)客戶端訪問的。? ? ?客戶端第一次請(qǐng)求到服務(wù)器連接,這個(gè)連接是沒有附帶任何東西的,沒有Cookie,沒有JSESSIONID。服務(wù)器端接收到請(qǐng)求后,會(huì)檢查這次請(qǐng)求有沒有傳過來(lái)JSESSIONID或者Cookie,如果沒有JSESSIONID和Cookie,則服務(wù)器端會(huì)創(chuàng)建一個(gè)Session,并生成一個(gè)與該Session相關(guān)聯(lián)的JSESSIONID返回給客戶端,客戶端會(huì)保存這個(gè)JSESSIONID,并生成一個(gè)與該JSESSIONID關(guān)聯(lián)的Cookie,第二次請(qǐng)求的時(shí)候,會(huì)把該Cookie(包含JSESSIONID)一起發(fā)送給服務(wù)器端,這次服務(wù)器發(fā)現(xiàn)這個(gè)請(qǐng)求有了Cookie,便從中取出JSESSIONID,然后根據(jù)這個(gè)JSESSIONID找到對(duì)應(yīng)的Session,這樣便把Http的無(wú)狀態(tài)連接變成了有狀態(tài)的連接。但是有時(shí)候?yàn)g覽器(即客戶端)會(huì)禁用Cookie,我們知道Cookie是通過Http的請(qǐng)求頭部的一個(gè)cookie字段傳過去的,如果禁用,那么便得不到這個(gè)值,JSESSIONID便不能通過Cookie傳入服務(wù)器端,當(dāng)然我們還有其他的解決辦法,url重寫和隱藏表單,url重寫就是把JSESSIONID附帶在url后面?zhèn)鬟^去。隱藏表單是在表單提交的時(shí)候傳入一個(gè)隱藏字段JSESSIONID。這兩種方式都能把JSESSIONID傳過去。? ? ?下面來(lái)看Tomcat是怎么實(shí)現(xiàn)以上流程的。從Tomcat源碼分析(二)--連接處理可知,連接請(qǐng)求會(huì)交給HttpProcessor的process方法處理,在此方法有這么幾句:[java]?view plaincopyprint?代碼沒什么說的,看url有沒有JSESSIONID,有就設(shè)置request的sessionid,沒有就設(shè)置為null。有再看parseHeaders方法:[java]?view plaincopyprint?
? ? ? ? 至此,Tomcat的Session管理的大部分東西也寫的差不多了,這里沒有寫StandardManager和StandardSession兩個(gè)類以及他們的實(shí)現(xiàn)接口,還有繼承關(guān)系等,是因?yàn)橛X得這篇文章已經(jīng)夠長(zhǎng)了,而且他們跟跟其他標(biāo)準(zhǔn)組件也差不多,無(wú)非是實(shí)現(xiàn)的具體功能不一樣,比如StandardSession還有過期處理等,不過它們也跟其他組件有各種關(guān)系,比如StandardManager就跟Context容器是關(guān)聯(lián)的。有機(jī)會(huì)再細(xì)細(xì)的說Session管理器其他的東西(持久化和分布式)。
總結(jié)
以上是生活随笔為你收集整理的Tomcat源码分析(九)--Session管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: eclipse中显示jquery或ext
- 下一篇: 最新银行定期存款利率表2022最新版,各