【tomcat】sessionId学习(未完待续)

  这里主要研究tomcat中session的管理方式以及sessionId的原理,下文将研究sessionid存到redis中以及基于redis以及redis实现session共享。

  平时也就是了解session是基于cookie实现的,cookie是保存在客户端,而session是保存在服务端,对其原来也没有深入理解。下面将深入理解。

1.什么是session

  对Tomcat而言,Session是一块在服务器开辟的内存空间,其内部的有一个ConcurrentHashMap,我们做setAttribute和removeAttribute的时候都操作的是此map。(补充一句,request对象的setAttribute也操作的是内部的一个Map)

public class StandardSession implements HttpSession, Session, Serializable {
    private static final long serialVersionUID = 1L;
    protected static final boolean STRICT_SERVLET_COMPLIANCE;
    protected static final boolean ACTIVITY_CHECK;
    protected static final boolean LAST_ACCESS_AT_START;
    protected static final String[] EMPTY_ARRAY;
    protected ConcurrentMap<String, Object> attributes = new ConcurrentHashMap();
...
}

2.Session的目的

Http协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;

Session的主要目的就是为了弥补Http的无状态特性。简单的说,就是服务器可以利用session存储客户端在同一个会话期间的一些操作记录;

Session中有一个ConcurrentMap,我们向Session中setAttribute和removeAttribute的时候操作的是此map。

 

3.简单的研究session的创建时机

3.1实现机制

先看两个问题,如下:
1、服务器如何判断客户端发送过来的请求是属于同一个会话?

答:用Session id区分,Session id相同的即认为是同一个会话,在Tomcat中Session id用JSESSIONID表示;

2、服务器、客户端如何获取Session id?Session id在其之间是如何传输的呢?

答:服务器第一次接收到请求时,开辟了一块Session空间(创建了Session对象),同时生成一个Session id,并通过响应头的Set-Cookie:“JSESSIONID=XXXXXXX”命令,向客户端发送要求设置cookie的响应;

客户端收到响应后,在本机客户端设置了一个JSESSIONID=XXXXXXX的cookie信息,该cookie的过期时间为浏览器会话结束;

接下来客户端每次向同一个网站发送请求时,请求头都会带上该cookie信息(包含Session id);

然后,服务器通过读取请求头中的Cookie信息,获取名称为JSESSIONID的值,得到此次请求的Session id;

ps:服务器只会在客户端第一次请求响应的时候,在响应头上添加Set-Cookie:“JSESSIONID=XXXXXXX”信息,接下来在同一个会话的第二第三次响应头里,是不会添加Set-Cookie:“JSESSIONID=XXXXXXX”信息的;

而客户端是会在每次请求头的cookie中带上JSESSIONID信息;

 

3.2创建时机简单研究

   我们知道request.getSession(boolean create)   获取session,并根据参数动态的获取session,如果传的参数是true的话不存在session就创建一个并返回一个session;如果传false,不存在session也不会创建,如下代码:

package com.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = LoggerFactory.getLogger(TestServlet.class);

    public TestServlet() {
        LOGGER.info("call servlet constructor!");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession(true);// 传true会创建一个并返回,false不会创建
        PrintWriter writer = response.getWriter();
        if (session == null) {
            writer.write("null");
        } else {
            writer.write(session.toString());
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

 

 

 

查看request.etSession(boolean create)的源码并分析:

  不带参数的getSession()里面调用的是getSession(true)方法。

    public HttpSession getSession() {
        return this.getSession(true);
    }

    public HttpSession getSession(boolean create) {
        if (this.crossContext) {
            if (this.context == null) {
                return null;
            } else if (this.session != null && this.session.isValid()) {
                return this.session.getSession();
            } else {
                HttpSession other = super.getSession(false);
                if (create && other == null) {
                    other = super.getSession(true);
                }

                if (other != null) {
                    Session localSession = null;

                    try {
                        localSession = this.context.getManager().findSession(other.getId());
                        if (localSession != null && !localSession.isValid()) {
                            localSession = null;
                        }
                    } catch (IOException arg4) {
                        ;
                    }

                    if (localSession == null && create) {
                        localSession = this.context.getManager().createSession(other.getId());
                    }

                    if (localSession != null) {
                        localSession.access();
                        this.session = localSession;
                        return this.session.getSession();
                    }
                }

                return null;
            }
        } else {
            return super.getSession(create);
        }
    }

 

上述结构图:

 

 

 

 

分析上面源码:

(1)当前的session存在并且有效(根据session的过期时间以及内部的一些属性进行判断)的话返回session

代码:

else if (this.session != null && this.session.isValid()) {
                return this.session.getSession();
            } 

 

 

查看this.session.getSession()的源码:(返回真正的session的代码)

下面是StandardSession中的代码:

    public HttpSession getSession() {
      if(this.facade == null) {
         if(SecurityUtil.isPackageProtectionEnabled()) {
            this.facade = (StandardSessionFacade)AccessController.doPrivileged(new 1(this, this));
         } else {
            this.facade = new StandardSessionFacade(this);
         }
      }

      return this.facade;
   }

 

 

看到代码是初始化了一个facade(门面)并且返回去。facade又是什么?

    protected transient StandardSessionFacade facade = null;

 

 

是一个实现HttpSession接口的类

package org.apache.catalina.session;

import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import org.apache.catalina.session.StandardSession;

public class StandardSessionFacade implements HttpSession {
    private HttpSession session = null;

    public StandardSessionFacade(StandardSession session) {
        this.session = session;
...
}

 

 

 (2)接下来研究session不存在的时候session创建并且返回的过程:

 

 

 

 

 

 

 

参考:http://www.cnblogs.com/chenpi/p/5434537.html

  https://www.cnblogs.com/nick-huang/p/6660232.html

  https://www.cnblogs.com/interdrp/p/4935614.html

  https://www.cnblogs.com/lonelydreamer/p/6169469.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值