`
113.com
  • 浏览: 81192 次
  • 来自: 广州
社区版块
存档分类
最新评论

Session对象的创建

    博客分类:
  • JSP
阅读更多
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就创建出来了。
 
分享到:
评论

相关推荐

    JSP 内置对象:session 对象.pptx

    4. `long getCreationTime()`: 返回Session对象创建的时间,以自1970年1月1日以来的毫秒数表示。 5. `long getLastAccessedTime()`: 获取最近一次用户请求或访问Session对象的时间,同样以毫秒数表示。 6. `String ...

    _基于Javaweb内置对象session的仿真.pdf

    Session对象的生命周期是指从Session对象创建到删除的整个过程。Servlet容器会在生命周期结束时将Session所占用的资源释放掉。Session的生命周期可以通过setTimeout方法来设置,也可以通过invalidate方法来手动删除...

    session对象及其常用方法

    8. 使用 Session 对象的 getCreationTime() 和 getLastAccessedTime() 方法可以获取会话创建的时间和最后访问的时间,但其返回值是毫秒,一般需要使用下面的转换来获取具体日期和时间。 Date creationTime = new ...

    Jsp内置对象session总结

    Session 对象是一个 JSP 内置对象,它在第一个 JSP 页面被装载时自动创建,完成会话期管理。从一个客户打开浏览器并连接到服务器开始,到客户关闭浏览器离开这个服务器结束,被称为一个会话。 Session 对象的 Id ...

    jsp中Session对象源码

    首先,`Session` 对象的创建通常发生在用户第一次访问受保护的资源时。服务器通过 `HttpServletRequest` 对象的 `getSession()` 方法来创建一个新的 `HttpSession` 实例。如果当前会话不存在,该方法会创建一个新的...

    Session对象讲解

    - 用户首次访问服务器时,服务器创建一个Session对象,并将Session ID返回给浏览器。 - 浏览器在后续的请求中携带这个Session ID,服务器根据ID找到对应的Session对象。 - 服务器在Session对象中存储用户的相关...

    servlet中关于session的理解

    #### Session对象创建与使用 当一个用户首次访问网站时,服务器会创建一个Session对象,并通过`HttpSession session = request.getSession(true);`这样的方式获取到这个Session对象。这里的参数`true`表示如果不...

    session对象存储

    在JSP中,我们通过`&lt;jsp:useBean&gt;`或`javax.servlet.http.HttpSession`接口来创建和操作Session对象。以下是一些基本操作: 1. **创建Session**: ```jsp &lt;% session = request.getSession(); %&gt; ``` 这行代码...

    session对象课件

    在ASP.NET的早期版本和2.0中,Session对象是由.NET Framework中的类实现的,它会在用户首次访问网站时自动创建,分配一个唯一的SessionID。这个ID是一个24个字符的字符串,由服务器随机生成,用于标识用户的身份。...

    JSP简易购物车 源码 session储存对象

    【JSP简易购物车 源码 session储存对象】是一个基于Java Server Pages(JSP)技术的简单购物车实现,它展示了如何利用session对象在Web应用程序中存储用户购物车的数据。这个项目对于初学者理解JSP和session的概念,...

    SSHnote session函数的对象状态转换

    当一个新的Java对象被创建,但尚未与Hibernate的Session关联时,它处于瞬时状态。这个状态下,对象没有被保存到数据库,任何对对象属性的修改不会自动同步到数据库。如果对象被删除,那么这些更改将永久丢失。 2. ...

    ASP技术常遇问题解答-如何将计数器的值赋给一个变量?.zip

    1. 使用Session对象创建计数器: ```vbscript If Session("counter") Is Nothing Then Session("counter") = 1 '初始化计数器 Else Session("counter") = Session("counter") + 1 '每次访问增加计数 End If %&gt; ``...

    SessionGWC.rar

    2. **设置Session属性**:一旦Session对象创建,我们就可以将数据以键值对的形式存储进去,例如`session.setAttribute("key", "value");`。这里的"key"是标识数据的唯一名称,"value"则是实际的数据,可以是任何Java...

    6 jsp内建对象之session

    **标题:“6 jsp内建对象之session”** 在JavaServer Pages (JSP) 技术中,`session`是六个内建对象之一,它在处理用户会话方面扮演着核心角色。会话跟踪是Web应用程序中一个重要的概念,尤其是在需要保持用户状态...

    asp.net实现统计在线人数的总结

    当用户开始新的会话时,Session对象创建;当用户会话结束时,Session对象销毁。利用Session对象,我们可以追踪用户何时进入网站以及何时离开,从而更新在线人数计数器。 #### 更新在线人数 在新会话开始时,我们...

    java发送邮件

    3. **创建Message对象**:使用Session对象创建一个Message实例,设置发件人、收件人、主题和邮件内容。 4. **创建Transport对象**:通过Session获取Transport,然后使用它来发送邮件。 以下是一个简单的Java发送...

    WEB开发 之 ASP Session 对象(1).docx

    在HTTP协议无状态的特性下,服务器无法直接识别出同一用户在不同页面间的交互,而Session对象通过创建唯一标识的Cookie来解决这个问题。每个用户访问网站时,服务器会为他们创建一个新的Session,这个Session包含了...

    Java Mail邮件发送源码下载

    2. 创建Transport:使用Session对象创建Transport实例,这个实例将负责实际的邮件发送操作。 3. 创建Message:通过MimeMessage类实例化一个Message对象,填充邮件内容,如收件人、抄送人、密送人、主题、正文等。...

Global site tag (gtag.js) - Google Analytics