大家都知道,在開(kāi)發(fā)一個(gè)互聯(lián)網(wǎng)應用的時(shí)候,為了達到一種服務(wù)端和客戶(hù)端有狀態(tài)的效果,需要有一個(gè)sessionid 來(lái)對客戶(hù)端進(jìn)行標志。很多時(shí)候,這是通過(guò)在客戶(hù)端防止session cookie實(shí)現的。但是如果客戶(hù)端禁用了cookie呢?這就需要通過(guò)urlrewrite或者其他方式來(lái)實(shí)現。于是我們可能就在應用里面不需要cookie了。既然不需要了當然是希望我們的應用不對cookie進(jìn)行處理。很遺憾的是,tomcat默認的是處理cookie的。每次請求過(guò)來(lái)的時(shí)候,都會(huì )解析request head里面的cookie信息,試圖從中發(fā)現sessionid的信息。于是我們就需要從應用服務(wù)器層面把這個(gè)"無(wú)用功"去掉。
tomcat(我讀的是tomcat6的源碼)可以通過(guò)設置來(lái)實(shí)現:
在conf/context.xml里面:<Context cookies = "false">。那么就禁用了cookie了。
在源碼級別的實(shí)現則是在CoyoteAdapter里面:
Java代碼
protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { // If session tracking via cookies has been disabled for the current // context, don't go looking for a session ID in a cookie as a cookie // from a parent context with a session ID may be present which would // overwrite the valid session ID encoded in the URL Context context = (Context) request.getMappingData().context; if (context != null && !context.getCookies()) return;
在這里面做了一個(gè)判斷,如果context禁用了cookie,那么就不做解析。如果使用cookie,那么試著(zhù)從cookie里面解析
sessionid,并且如果存在的話(huà)覆蓋request里面已有的(從url里面解析出來(lái)的)或者還沒(méi)有的sesssionid.
這個(gè)方法的入口是在CoyoteAdapter的service方法里面,這個(gè)方法沿著(zhù)tomcat6的component 鏈傳遞處理request 和response,結構圖如下:
service--------->EngineValue
|
HostValue
|
ContextValue
|
WrapperValue
這實(shí)際就是一個(gè)chain of resposibility模式,負責對request和response進(jìn)行各自職責范圍內的包裝和處理。
最后的WrapperValue執行調用servlet處理請求的步驟。
好了,上面簡(jiǎn)單解釋了cookie的處理,那么下面就是session了。
不管通過(guò)什么方式,通過(guò)cookie也好,通過(guò)urlrewrite也好,session在需要的時(shí)候是肯定要產(chǎn)生的.
但是如果我們不需要呢?比如恰好我們要展現給客戶(hù)的首頁(yè)就是jsp的,客戶(hù)不需要登錄就能瀏覽這個(gè)頁(yè)面的內容。
那么這個(gè)時(shí)候對于客戶(hù)的請求創(chuàng )建session就是沒(méi)有必要的了。
一種常用的不創(chuàng )建session的方法是在jsp頁(yè)面頭上加一句:
<%@ page session=”false”>
這樣在請求這個(gè)頁(yè)面的時(shí)候就不產(chǎn)生session了。
這個(gè)在tomcat內部是怎么實(shí)現的呢?
首先明確一點(diǎn),jsp在本質(zhì)上是httpservlet,在/tomcat/work目錄下面你會(huì )發(fā)現有跟自己的應用相同目錄結構的一些文件,其中的jsp文件都變成了class文件,這實(shí)際是被jspcompiler編譯過(guò)的。上面提到了WrapperValue會(huì )最終調用
servlet處理request。有興趣的同學(xué)可以跟蹤一下,會(huì )發(fā)現到了調用jsp對應的servlet(JspServlet)(這個(gè)是在tomcat/conf/web.xml里面配置的,對于.jsp,對應的servlet是jspservlet)時(shí),最終會(huì )著(zhù)落在
tomcat下面實(shí)現了PageContext接口的特定于jsp specification的實(shí)現類(lèi):PageContextImpl。
在這個(gè)類(lèi)的initialize里面有這么一句:
Java代碼
if (request instanceof HttpServletRequest && needsSession) this.session = ((HttpServletRequest) request).getSession();
這句的意思就是,有session獲取session,沒(méi)session新建一個(gè)。而通常,這個(gè)地方也是客戶(hù)端與tomcat下面的應用交互時(shí)產(chǎn)生session的入口。
這句里面的needsSession就是之前提到的jsp頁(yè)面上配置的值,默認是true.所以如果想在訪(fǎng)問(wèn)某個(gè)頁(yè)面時(shí)不產(chǎn)生session,只需要設置成false就可以了。