当前位置: 代码迷 >> Web前端 >> Tomcat的Session管理(1) - Session的生成
  详细解决方案

Tomcat的Session管理(1) - Session的生成

热度:726   发布时间:2013-12-07 22:19:20.0
Tomcat的Session管理(一) - Session的生成

Session对象的创建一般是源于这样的一条语句:
Session session = request.getSession(false);或者Session session = request.getSession();如果不在乎服务器压力可能多那么一点点的话。

在Tomcat的实现中,这个request是org.apache.catalina.connector.Request类的包装类 org.apache.catalina.connector.RequestFacade的对象,它的两个#getSession()方法如下:

Java代码 ?收藏代码
  1. public?HttpSession?getSession(boolean?create)?{??
  2. ????if?(request?==?null)?{??
  3. ????????throw?new?IllegalStateException(??
  4. ????????????????????????sm.getString("requestFacade.nullRequest"));??
  5. ????}??
  6. ??
  7. ????if?(SecurityUtil.isPackageProtectionEnabled()){??
  8. ????????return?(HttpSession)AccessController.??
  9. ????????????doPrivileged(new?GetSessionPrivilegedAction(create));??
  10. ????}?else?{??
  11. ????????return?request.getSession(create);??
  12. ????}??
  13. }??



Java代码 ?收藏代码
  1. public?HttpSession?getSession()?{??
  2. ????if?(request?==?null)?{??
  3. ????????throw?new?IllegalStateException(??
  4. ????????????????????????sm.getString("requestFacade.nullRequest"));??
  5. ????}??
  6. ??
  7. ????return?getSession(true);??
  8. }??



其实差不太多,最后都会进入org.apache.catalina.connector.Request的#getSession()方法。这个方法的源代码如下:

Java代码 ?收藏代码
  1. public?HttpSession?getSession(boolean?create)?{??
  2. ????Session?session?=?doGetSession(create);??
  3. ????if?(session?!=?null)?{??
  4. ????????return?session.getSession();??
  5. ????}?else?{??
  6. ????????return?null;??
  7. ????}??
  8. }??



然后调用就到了#doGetSession()这个方法了。源代码如下

Java代码 ?收藏代码
  1. protected?Session?doGetSession(boolean?create)?{??
  2. ????//?没有Context的话直接返回null??
  3. ????if?(context?==?null)??
  4. ????????return?(null);??
  5. ??
  6. ????//?判断Session是否有效??
  7. ????if?((session?!=?null)?&&?!session.isValid())??
  8. ????????session?=?null;??
  9. ????if?(session?!=?null)??
  10. ????????return?(session);??
  11. ??
  12. ????//?返回Manager对象,这里是StandardManager类的对象??
  13. ????Manager?manager?=?null;??
  14. ????if?(context?!=?null)??
  15. ????????manager?=?context.getManager();??
  16. ????if?(manager?==?null)??
  17. ????????return?(null);?//?Sessions?are?not?supported??
  18. ????//?判断是否有SessionID??
  19. ????if?(requestedSessionId?!=?null)?{??
  20. ????????try?{??
  21. ????????????//?在Manager中根据SessionID查找Session??
  22. ????????????session?=?manager.findSession(requestedSessionId);??
  23. ????????}?catch?(IOException?e)?{??
  24. ????????????session?=?null;??
  25. ????????}??
  26. ????????if?((session?!=?null)?&&?!session.isValid())??
  27. ????????????session?=?null;??
  28. ????????if?(session?!=?null)?{??
  29. ????????????//?更新访问时间??
  30. ????????????session.access();??
  31. ????????????return?(session);??
  32. ????????}??
  33. ????}??
  34. ??
  35. ????//?创建新的Session??
  36. ????if?(!create)??
  37. ????????return?(null);??
  38. ????if?((context?!=?null)?&&?(response?!=?null)?&&?context.getCookies()??
  39. ????????????&&?response.getResponse().isCommitted())?{??
  40. ????????throw?new?IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));??
  41. ????}??
  42. ??
  43. ????//?判断是否使用?"/"?作为Session?Cookie的存储路径?并且?是否SessionID来自Cookie??
  44. ????if?(connector.getEmptySessionPath()?&&?isRequestedSessionIdFromCookie())?{??
  45. ????????//?创建Session??
  46. ????????session?=?manager.createSession(getRequestedSessionId());??
  47. ????}?else?{??
  48. ????????session?=?manager.createSession(null);??
  49. ????}??
  50. ??
  51. ????//?创建一个新的Session?Cookies??
  52. ????if?((session?!=?null)?&&?(getContext()?!=?null)?&&?getContext().getCookies())?{??
  53. ????????Cookie?cookie?=?new?Cookie(Globals.SESSION_COOKIE_NAME,?session.getIdInternal());??
  54. ????????//?配置Session?Cookie??
  55. ????????configureSessionCookie(cookie);??
  56. ????????//?在响应中加入Session?Cookie??
  57. ????????response.addCookieInternal(cookie);??
  58. ????}??
  59. ??
  60. ????if?(session?!=?null)?{??
  61. ????????//?更新访问时间??
  62. ????????session.access();??
  63. ????????return?(session);??
  64. ????}?else?{??
  65. ????????return?(null);??
  66. ????}??
  67. ??
  68. }??


这个方法说明了Session创建的大致过程,首先判断requestedSessionId是否存在,如果存在,那么根据这个ID去查找 Session对象。如果requestedSessionId不存在或者没有取到Session,并且传递给#getSession(boolean) 的参数为真,那么要创建一个新的Session,并且给客户端写回去一个Session Cookie。

首先,我感兴趣的是requestedSessionId的赋值,它到底是什么时候被赋值的呢?

还要向回看Tomcat的请求处理过程,请求曾到过这一步,org.apache.catalina.connector.CoyoteAdapter的#service()方法。里边有这样一句方法调用:postParseRequest(req, request, res, response)。就是这一步处理了SessionID的获取,这个方法调用了#parseSessionId()和 parseSessionCookiesId()这两个方法,就是它对Session ID进行了提取,源代码分别如下:

Java代码 ?收藏代码
  1. protected?void?parseSessionId(org.apache.coyote.Request?req,?Request?request)?{??
  2. ??
  3. ????ByteChunk?uriBC?=?req.requestURI().getByteChunk();??
  4. ????//?判断URL中是不是有";jsessionid="这个字符串??
  5. ????int?semicolon?=?uriBC.indexOf(match,?0,?match.length(),?0);??
  6. ??
  7. ????if?(semicolon?>?0)?{??
  8. ????????//?Parse?session?ID,?and?extract?it?from?the?decoded?request?URI??
  9. ????????//?在URL中提取Session?ID??
  10. ????????int?start?=?uriBC.getStart();??
  11. ????????int?end?=?uriBC.getEnd();??
  12. ??
  13. ????????int?sessionIdStart?=?semicolon?+?match.length();??
  14. ????????int?semicolon2?=?uriBC.indexOf(';',?sessionIdStart);??
  15. ????????if?(semicolon2?>=?0)?{??
  16. ????????????request.setRequestedSessionId(new?String(uriBC.getBuffer(),?start?+?sessionIdStart,??
  17. ????????????????????semicolon2?-?sessionIdStart));??
  18. ????????????byte[]?buf?=?uriBC.getBuffer();??
  19. ????????????for?(int?i?=?0;?i?<?end?-?start?-?semicolon2;?i++)?{??
  20. ????????????????buf[start?+?semicolon?+?i]?=?buf[start?+?i?+?semicolon2];??
  21. ????????????}??
  22. ????????????uriBC.setBytes(buf,?start,?end?-?start?-?semicolon2?+?semicolon);??
  23. ????????}?else?{??
  24. ????????????request.setRequestedSessionId(new?String(uriBC.getBuffer(),?start?+?sessionIdStart,??
  25. ????????????????????(end?-?start)?-?sessionIdStart));??
  26. ????????????uriBC.setEnd(start?+?semicolon);??
  27. ????????}??
  28. ????????//?设定Session?ID来自于URL??
  29. ????????request.setRequestedSessionURL(true);??
  30. ??
  31. ????}?else?{??
  32. ????????request.setRequestedSessionId(null);??
  33. ????????request.setRequestedSessionURL(false);??
  34. ????}??
  35. ??
  36. }??



Java代码 ?收藏代码
  1. protected?void?parseSessionCookiesId(org.apache.coyote.Request?req,?Request?request)?{??
  2. ????Context?context?=?(Context)?request.getMappingData().context;??
  3. ????if?(context?!=?null?&&?!context.getCookies())??
  4. ????????return;??
  5. ??
  6. ????//?返回Cookie??
  7. ????Cookies?serverCookies?=?req.getCookies();??
  8. ????int?count?=?serverCookies.getCookieCount();??
  9. ????if?(count?<=?0)??
  10. ????????return;??
  11. ??
  12. ????for?(int?i?=?0;?i?<?count;?i++)?{??
  13. ????????ServerCookie?scookie?=?serverCookies.getCookie(i);??
  14. ????????//?判断是否有JSESSIONID这个名字的Cookie??
  15. ????????if?(scookie.getName().equals(Globals.SESSION_COOKIE_NAME))?{??
  16. ????????????//?Override?anything?requested?in?the?URL??
  17. ????????????if?(!request.isRequestedSessionIdFromCookie())?{??
  18. ????????????????//?设定Session?ID??
  19. ????????????????convertMB(scookie.getValue());??
  20. ????????????????request.setRequestedSessionId(scookie.getValue().toString());??
  21. ????????????????//?如果之前在URL中读到了SessionID,那么会覆盖它??
  22. ????????????????request.setRequestedSessionCookie(true);??
  23. ????????????????request.setRequestedSessionURL(false);??
  24. ????????????????if?(log.isDebugEnabled())??
  25. ????????????????????log.debug("?Requested?cookie?session?id?is?"?+?request.getRequestedSessionId());??
  26. ????????????}?else?{??
  27. ????????????????if?(!request.isRequestedSessionIdValid())?{??
  28. ????????????????????convertMB(scookie.getValue());??
  29. ????????????????????request.setRequestedSessionId(scookie.getValue().toString());??
  30. ????????????????}??
  31. ????????????}??
  32. ????????}??
  33. ????}??
  34. ??
  35. }??


Tomcat就是通过上边的两个方法读到URL或者Cookie中存放的Session ID的。

了解了Session ID的获取,下面要看一下Session的查找过程,就是org.apache.catalina.session.StandardManager的#findSession()方法。这个方法是在它的基类中定义的,源代码如下:

Java代码 ?收藏代码
  1. public?Session?findSession(String?id)?throws?IOException?{??
  2. ????if?(id?==?null)??
  3. ????????return?(null);??
  4. ????return?(Session)?sessions.get(id);??
  5. }??


代码很短,其中sessions是一个ConcurrentHashMap<String, Session>对象。那么这个sessions的对象是什么时候载入的Session呢?

启动的时候!可以看一下StandardManager#start()方法。最后调用了#load()方法,这个就是载入Session的方法了:

Java代码 ?收藏代码
  1. public?void?load()?throws?ClassNotFoundException,?IOException?{??
  2. ????if?(SecurityUtil.isPackageProtectionEnabled())?{??
  3. ????????try?{??
  4. ????????????AccessController.doPrivileged(new?PrivilegedDoLoad());??
  5. ????????}?catch?(PrivilegedActionException?ex)?{??
  6. ????????????Exception?exception?=?ex.getException();??
  7. ????????????if?(exception?instanceof?ClassNotFoundException)?{??
  8. ????????????????throw?(ClassNotFoundException)?exception;??
  9. ????????????}?else?if?(exception?instanceof?IOException)?{??
  10. ????????????????throw?(IOException)?exception;??
  11. ????????????}??
  12. ????????????if?(log.isDebugEnabled())??
  13. ????????????????log.debug("Unreported?exception?in?load()?"?+?exception);??
  14. ????????}??
  15. ????}?else?{??
  16. ????????doLoad();??
  17. ????}??
  18. }??


最后调用了#doLoad()方法来具体的载入Session,源代码如下:

Java代码 ?收藏代码
  1. protected?void?doLoad()?throws?ClassNotFoundException,?IOException?{??
  2. ????if?(log.isDebugEnabled())??
  3. ????????log.debug("Start:?Loading?persisted?sessions");??
  4. ??
  5. ????//?清空Map??
  6. ????sessions.clear();??
  7. ??
  8. ????//?对应work/Catalina/localhost/%app?name%/SESSIONS.ser文件??
  9. ????File?file?=?file();??
  10. ????if?(file?==?null)??
  11. ????????return;??
  12. ????if?(log.isDebugEnabled())??
  13. ????????log.debug(sm.getString("standardManager.loading",?pathname));??
  14. ????FileInputStream?fis?=?null;??
  15. ????ObjectInputStream?ois?=?null;??
  16. ????Loader?loader?=?null;??
  17. ????ClassLoader?classLoader?=?null;??
  18. ????try?{??
  19. ????????//?载入Session缓存文件??
  20. ????????fis?=?new?FileInputStream(file.getAbsolutePath());??
  21. ????????BufferedInputStream?bis?=?new?BufferedInputStream(fis);??
  22. ????????if?(container?!=?null)??
  23. ????????????loader?=?container.getLoader();??
  24. ????????if?(loader?!=?null)??
  25. ????????????classLoader?=?loader.getClassLoader();??
  26. ????????if?(classLoader?!=?null)?{??
  27. ????????????if?(log.isDebugEnabled())??
  28. ????????????????log.debug("Creating?custom?object?input?stream?for?class?loader?");??
  29. ????????????ois?=?new?CustomObjectInputStream(bis,?classLoader);??
  30. ????????}?else?{??
  31. ????????????if?(log.isDebugEnabled())??
  32. ????????????????log.debug("Creating?standard?object?input?stream");??
  33. ????????????ois?=?new?ObjectInputStream(bis);??
  34. ????????}??
  35. ????}?catch?(FileNotFoundException?e)?{??
  36. ????????if?(log.isDebugEnabled())??
  37. ????????????log.debug("No?persisted?data?file?found");??
  38. ????????return;??
  39. ????}?catch?(IOException?e)?{??
  40. ????????log.error(sm.getString("standardManager.loading.ioe",?e),?e);??
  41. ????????if?(ois?!=?null)?{??
  42. ????????????try?{??
  43. ????????????????ois.close();??
  44. ????????????}?catch?(IOException?f)?{??
  45. ????????????????;??
  46. ????????????}??
  47. ????????????ois?=?null;??
  48. ????????}??
  49. ????????throw?e;??
  50. ????}??
  51. ??
  52. ????synchronized?(sessions)?{??
  53. ????????try?{??
  54. ????????????//?读出Session个数??
  55. ????????????Integer?count?=?(Integer)?ois.readObject();??
  56. ????????????int?n?=?count.intValue();??
  57. ????????????if?(log.isDebugEnabled())??
  58. ????????????????log.debug("Loading?"?+?n?+?"?persisted?sessions");??
  59. ????????????//??读入Session??
  60. ????????????for?(int?i?=?0;?i?<?n;?i++)?{??
  61. ????????????????StandardSession?session?=?getNewSession();??
  62. ????????????????session.readObjectData(ois);??
  63. ????????????????session.setManager(this);??
  64. ????????????????sessions.put(session.getIdInternal(),?session);??
  65. ????????????????session.activate();??
  66. ????????????????sessionCounter++;??
  67. ????????????}??
  68. ????????}?catch?(ClassNotFoundException?e)?{??
  69. ????????????log.error(sm.getString("standardManager.loading.cnfe",?e),?e);??
  70. ????????????if?(ois?!=?null)?{??
  71. ????????????????try?{??
  72. ????????????????????ois.close();??
  73. ????????????????}?catch?(IOException?f)?{??
  74. ????????????????????;??
  75. ????????????????}??
  76. ????????????????ois?=?null;??
  77. ????????????}??
  78. ????????????throw?e;??
  79. ????????}?catch?(IOException?e)?{??
  80. ????????????log.error(sm.getString("standardManager.loading.ioe",?e),?e);??
  81. ????????????if?(ois?!=?null)?{??
  82. ????????????????try?{??
  83. ????????????????????ois.close();??
  84. ????????????????}?catch?(IOException?f)?{??
  85. ????????????????????;??
  86. ????????????????}??
  87. ????????????????ois?=?null;??
  88. ????????????}??
  89. ????????????throw?e;??
  90. ????????}?finally?{??
  91. ????????????try?{??
  92. ????????????????if?(ois?!=?null)??
  93. ????????????????????ois.close();??
  94. ????????????}?catch?(IOException?f)?{??
  95. ????????????}??
  96. ??
  97. ????????????//?删除Session缓存文件??
  98. ????????????if?(file?!=?null?&&?file.exists())??
  99. ????????????????file.delete();??
  100. ????????}??
  101. ????}??
  102. ??
  103. ????if?(log.isDebugEnabled())??
  104. ????????log.debug("Finish:?Loading?persisted?sessions");??
  105. }??


大致知道了Session的读取过程,后面就是Session没找到时创建Session的过程了。具体就是org.apache.catalina.session.StandardManager的#createSession()方法:

Java代码 ?收藏代码
  1. public?Session?createSession(String?sessionId)?{??
  2. ????if?((maxActiveSessions?>=?0)?&&?(sessions.size()?>=?maxActiveSessions))?{??
  3. ????????rejectedSessions++;??
  4. ????????throw?new?IllegalStateException(sm.getString("standardManager.createSession.ise"));??
  5. ????}??
  6. ????return?(super.createSession(sessionId));??
  7. }??


最后调用到了它的基类的#createSession()方法了。

Java代码 ?收藏代码
  1. public?Session?createSession(String?sessionId)?{??
  2. ????//?创建一个新的Session??
  3. ????Session?session?=?createEmptySession();??
  4. ??
  5. ????//?初始化Session的属性??
  6. ????session.setNew(true);??
  7. ????session.setValid(true);??
  8. ????session.setCreationTime(System.currentTimeMillis());??
  9. ????session.setMaxInactiveInterval(this.maxInactiveInterval);??
  10. ????//?如果Session?ID为null,那么就生成一个??
  11. ????if?(sessionId?==?null)?{??
  12. ????????sessionId?=?generateSessionId();??
  13. ????}??
  14. ????session.setId(sessionId);??
  15. ????sessionCounter++;??
  16. ??
  17. ????return?(session);??
  18. ??
  19. }??


通过上述过程,一个新的Session就创建出来了。

  相关解决方案