注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

眼睛想旅行

技术就是我的生命与信仰!

 
 
 

日志

 
 
关于我

精通C,C++,python,Erlang。并熟悉各种其他编程语言,用cocos2dx游戏引擎作过几个项目。会MySQL增删改查,了解OpenGL渲染原理。懂单片机,能设计数字电路系统,会画电路图和设计电路板。喜欢了解最新前沿技术,并持续关注和学习新技术。

网易考拉推荐

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

2014-02-24 17:34:14|  分类: 游戏编程和服务器 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

转自:http://zddava.iteye.com/blog/311053

Session对象的创建一般是源于这样的一条语句:
Session session = request.getSession(false);或者Session session = request.getSession();如果不在乎服务器压力可能多那么一点点的话。
在Tomcat的实现中,这个request是org.apache.catalina.connector.Request类的包装类org.apache.catalina.connector.RequestFacade的对象,它的两个#getSession()方法如下:
Java代码

public HttpSession getSession(boolean create) {  
    if (request == null) {  
        throw new IllegalStateException(  
                        sm.getString("requestFacade.nullRequest"));  
    }  
  
    if (SecurityUtil.isPackageProtectionEnabled()){  
        return (HttpSession)AccessController.  
            doPrivileged(new GetSessionPrivilegedAction(create));  
    } else {  
        return request.getSession(create);  
    }  
}  

    public HttpSession getSession(boolean create) {
        if (request == null) {
            throw new IllegalStateException(
                            sm.getString("requestFacade.nullRequest"));
        }

        if (SecurityUtil.isPackageProtectionEnabled()){
            return (HttpSession)AccessController.
                doPrivileged(new GetSessionPrivilegedAction(create));
        } else {
            return request.getSession(create);
        }
    }

Java代码 

public HttpSession getSession() {  
    if (request == null) {  
        throw new IllegalStateException(  
                        sm.getString("requestFacade.nullRequest"));  
    }  
  
    return getSession(true);  
}  

    public HttpSession getSession() {
        if (request == null) {
            throw new IllegalStateException(
                            sm.getString("requestFacade.nullRequest"));
        }

        return getSession(true);
    }



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

public HttpSession getSession(boolean create) {  
    Session session = doGetSession(create);  
    if (session != null) {  
        return session.getSession();  
    } else {  
        return null;  
    }  
}  

    public HttpSession getSession(boolean create) {
        Session session = doGetSession(create);
        if (session != null) {
            return session.getSession();
        } else {
            return null;
        }
    }



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

protected Session doGetSession(boolean create) {  
    // 没有Context的话直接返回null  
    if (context == null)  
        return (null);  
  
    // 判断Session是否有效  
    if ((session != null) && !session.isValid())  
        session = null;  
    if (session != null)  
        return (session);  
  
    // 返回Manager对象,这里是StandardManager类的对象  
    Manager manager = null;  
    if (context != null)  
        manager = context.getManager();  
    if (manager == null)  
        return (null); // Sessions are not supported  
    // 判断是否有SessionID  
    if (requestedSessionId != null) {  
        try {  
            // 在Manager中根据SessionID查找Session  
            session = manager.findSession(requestedSessionId);  
        } catch (IOException e) {  
            session = null;  
        }  
        if ((session != null) && !session.isValid())  
            session = null;  
        if (session != null) {  
            // 更新访问时间  
            session.access();  
            return (session);  
        }  
    }  
  
    // 创建新的Session  
    if (!create)  
        return (null);  
    if ((context != null) && (response != null) && context.getCookies()  
            && response.getResponse().isCommitted()) {  
        throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));  
    }  
  
    // 判断是否使用 "/" 作为Session Cookie的存储路径 并且 是否SessionID来自Cookie  
    if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) {  
        // 创建Session  
        session = manager.createSession(getRequestedSessionId());  
    } else {  
        session = manager.createSession(null);  
    }  
  
    // 创建一个新的Session Cookies  
    if ((session != null) && (getContext() != null) && getContext().getCookies()) {  
        Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, session.getIdInternal());  
        // 配置Session Cookie  
        configureSessionCookie(cookie);  
        // 在响应中加入Session Cookie  
        response.addCookieInternal(cookie);  
    }  
  
    if (session != null) {  
        // 更新访问时间  
        session.access();  
        return (session);  
    } else {  
        return (null);  
    }  
  
}  

	protected Session doGetSession(boolean create) {
		// 没有Context的话直接返回null
		if (context == null)
			return (null);

		// 判断Session是否有效
		if ((session != null) && !session.isValid())
			session = null;
		if (session != null)
			return (session);

		// 返回Manager对象,这里是StandardManager类的对象
		Manager manager = null;
		if (context != null)
			manager = context.getManager();
		if (manager == null)
			return (null); // Sessions are not supported
		// 判断是否有SessionID
		if (requestedSessionId != null) {
			try {
				// 在Manager中根据SessionID查找Session
				session = manager.findSession(requestedSessionId);
			} catch (IOException e) {
				session = null;
			}
			if ((session != null) && !session.isValid())
				session = null;
			if (session != null) {
				// 更新访问时间
				session.access();
				return (session);
			}
		}

		// 创建新的Session
		if (!create)
			return (null);
		if ((context != null) && (response != null) && context.getCookies()
				&& response.getResponse().isCommitted()) {
			throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));
		}

		// 判断是否使用 "/" 作为Session Cookie的存储路径 并且 是否SessionID来自Cookie
		if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) {
			// 创建Session
			session = manager.createSession(getRequestedSessionId());
		} else {
			session = manager.createSession(null);
		}

		// 创建一个新的Session Cookies
		if ((session != null) && (getContext() != null) && getContext().getCookies()) {
			Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, session.getIdInternal());
			// 配置Session Cookie
			configureSessionCookie(cookie);
			// 在响应中加入Session Cookie
			response.addCookieInternal(cookie);
		}

		if (session != null) {
			// 更新访问时间
			session.access();
			return (session);
		} else {
			return (null);
		}

	}



这个方法说明了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代码

protected void parseSessionId(org.apache.coyote.Request req, Request request) {  
  
    ByteChunk uriBC = req.requestURI().getByteChunk();  
    // 判断URL中是不是有";jsessionid="这个字符串  
    int semicolon = uriBC.indexOf(match, 0, match.length(), 0);  
  
    if (semicolon > 0) {  
        // Parse session ID, and extract it from the decoded request URI  
        // 在URL中提取Session ID  
        int start = uriBC.getStart();  
        int end = uriBC.getEnd();  
  
        int sessionIdStart = semicolon + match.length();  
        int semicolon2 = uriBC.indexOf(';', sessionIdStart);  
        if (semicolon2 >= 0) {  
            request.setRequestedSessionId(new String(uriBC.getBuffer(), start + sessionIdStart,  
                    semicolon2 - sessionIdStart));  
            byte[] buf = uriBC.getBuffer();  
            for (int i = 0; i < end - start - semicolon2; i++) {  
                buf[start + semicolon + i] = buf[start + i + semicolon2];  
            }  
            uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);  
        } else {  
            request.setRequestedSessionId(new String(uriBC.getBuffer(), start + sessionIdStart,  
                    (end - start) - sessionIdStart));  
            uriBC.setEnd(start + semicolon);  
        }  
        // 设定Session ID来自于URL  
        request.setRequestedSessionURL(true);  
  
    } else {  
        request.setRequestedSessionId(null);  
        request.setRequestedSessionURL(false);  
    }  
  
}  

	protected void parseSessionId(org.apache.coyote.Request req, Request request) {

		ByteChunk uriBC = req.requestURI().getByteChunk();
		// 判断URL中是不是有";jsessionid="这个字符串
		int semicolon = uriBC.indexOf(match, 0, match.length(), 0);

		if (semicolon > 0) {
			// Parse session ID, and extract it from the decoded request URI
			// 在URL中提取Session ID
			int start = uriBC.getStart();
			int end = uriBC.getEnd();

			int sessionIdStart = semicolon + match.length();
			int semicolon2 = uriBC.indexOf(';', sessionIdStart);
			if (semicolon2 >= 0) {
				request.setRequestedSessionId(new String(uriBC.getBuffer(), start + sessionIdStart,
						semicolon2 - sessionIdStart));
				byte[] buf = uriBC.getBuffer();
				for (int i = 0; i < end - start - semicolon2; i++) {
					buf[start + semicolon + i] = buf[start + i + semicolon2];
				}
				uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
			} else {
				request.setRequestedSessionId(new String(uriBC.getBuffer(), start + sessionIdStart,
						(end - start) - sessionIdStart));
				uriBC.setEnd(start + semicolon);
			}
			// 设定Session ID来自于URL
			request.setRequestedSessionURL(true);

		} else {
			request.setRequestedSessionId(null);
			request.setRequestedSessionURL(false);
		}

	}


Java代码

protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {  
    Context context = (Context) request.getMappingData().context;  
    if (context != null && !context.getCookies())  
        return;  
  
    // 返回Cookie  
    Cookies serverCookies = req.getCookies();  
    int count = serverCookies.getCookieCount();  
    if (count <= 0)  
        return;  
  
    for (int i = 0; i < count; i++) {  
        ServerCookie scookie = serverCookies.getCookie(i);  
        // 判断是否有JSESSIONID这个名字的Cookie  
        if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {  
            // Override anything requested in the URL  
            if (!request.isRequestedSessionIdFromCookie()) {  
                // 设定Session ID  
                convertMB(scookie.getValue());  
                request.setRequestedSessionId(scookie.getValue().toString());  
                // 如果之前在URL中读到了SessionID,那么会覆盖它  
                request.setRequestedSessionCookie(true);  
                request.setRequestedSessionURL(false);  
                if (log.isDebugEnabled())  
                    log.debug(" Requested cookie session id is " + request.getRequestedSessionId());  
            } else {  
                if (!request.isRequestedSessionIdValid()) {  
                    convertMB(scookie.getValue());  
                    request.setRequestedSessionId(scookie.getValue().toString());  
                }  
            }  
        }  
    }  
  
}  

	protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {
		Context context = (Context) request.getMappingData().context;
		if (context != null && !context.getCookies())
			return;

		// 返回Cookie
		Cookies serverCookies = req.getCookies();
		int count = serverCookies.getCookieCount();
		if (count <= 0)
			return;

		for (int i = 0; i < count; i++) {
			ServerCookie scookie = serverCookies.getCookie(i);
			// 判断是否有JSESSIONID这个名字的Cookie
			if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
				// Override anything requested in the URL
				if (!request.isRequestedSessionIdFromCookie()) {
					// 设定Session ID
					convertMB(scookie.getValue());
					request.setRequestedSessionId(scookie.getValue().toString());
					// 如果之前在URL中读到了SessionID,那么会覆盖它
					request.setRequestedSessionCookie(true);
					request.setRequestedSessionURL(false);
					if (log.isDebugEnabled())
						log.debug(" Requested cookie session id is " + request.getRequestedSessionId());
				} else {
					if (!request.isRequestedSessionIdValid()) {
						convertMB(scookie.getValue());
						request.setRequestedSessionId(scookie.getValue().toString());
					}
				}
			}
		}

	}



Tomcat就是通过上边的两个方法读到URL或者Cookie中存放的Session ID的。
了解了Session ID的获取,下面要看一下Session的查找过程,就是org.apache.catalina.session.StandardManager的#findSession()方法。这个方法是在它的基类中定义的,源代码如下:
Java代码

public Session findSession(String id) throws IOException {  
    if (id == null)  
        return (null);  
    return (Session) sessions.get(id);  
}  

    public Session findSession(String id) throws IOException {
        if (id == null)
            return (null);
        return (Session) sessions.get(id);
    }




代码很短,其中sessions是一个ConcurrentHashMap<String, Session>对象。那么这个sessions的对象是什么时候载入的Session呢?
启动的时候!可以看一下StandardManager#start()方法。最后调用了#load()方法,这个就是载入Session的方法了:
Java代码

public void load() throws ClassNotFoundException, IOException {  
    if (SecurityUtil.isPackageProtectionEnabled()) {  
        try {  
            AccessController.doPrivileged(new PrivilegedDoLoad());  
        } catch (PrivilegedActionException ex) {  
            Exception exception = ex.getException();  
            if (exception instanceof ClassNotFoundException) {  
                throw (ClassNotFoundException) exception;  
            } else if (exception instanceof IOException) {  
                throw (IOException) exception;  
            }  
            if (log.isDebugEnabled())  
                log.debug("Unreported exception in load() " + exception);  
        }  
    } else {  
        doLoad();  
    }  
}  

	public void load() throws ClassNotFoundException, IOException {
		if (SecurityUtil.isPackageProtectionEnabled()) {
			try {
				AccessController.doPrivileged(new PrivilegedDoLoad());
			} catch (PrivilegedActionException ex) {
				Exception exception = ex.getException();
				if (exception instanceof ClassNotFoundException) {
					throw (ClassNotFoundException) exception;
				} else if (exception instanceof IOException) {
					throw (IOException) exception;
				}
				if (log.isDebugEnabled())
					log.debug("Unreported exception in load() " + exception);
			}
		} else {
			doLoad();
		}
	}




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

Java代码

protected void doLoad() throws ClassNotFoundException, IOException {  
    if (log.isDebugEnabled())  
        log.debug("Start: Loading persisted sessions");  
  
    // 清空Map  
    sessions.clear();  
  
    // 对应work/Catalina/localhost/%app name%/SESSIONS.ser文件  
    File file = file();  
    if (file == null)  
        return;  
    if (log.isDebugEnabled())  
        log.debug(sm.getString("standardManager.loading", pathname));  
    FileInputStream fis = null;  
    ObjectInputStream ois = null;  
    Loader loader = null;  
    ClassLoader classLoader = null;  
    try {  
        // 载入Session缓存文件  
        fis = new FileInputStream(file.getAbsolutePath());  
        BufferedInputStream bis = new BufferedInputStream(fis);  
        if (container != null)  
            loader = container.getLoader();  
        if (loader != null)  
            classLoader = loader.getClassLoader();  
        if (classLoader != null) {  
            if (log.isDebugEnabled())  
                log.debug("Creating custom object input stream for class loader ");  
            ois = new CustomObjectInputStream(bis, classLoader);  
        } else {  
            if (log.isDebugEnabled())  
                log.debug("Creating standard object input stream");  
            ois = new ObjectInputStream(bis);  
        }  
    } catch (FileNotFoundException e) {  
        if (log.isDebugEnabled())  
            log.debug("No persisted data file found");  
        return;  
    } catch (IOException e) {  
        log.error(sm.getString("standardManager.loading.ioe", e), e);  
        if (ois != null) {  
            try {  
                ois.close();  
            } catch (IOException f) {  
                ;  
            }  
            ois = null;  
        }  
        throw e;  
    }  
  
    synchronized (sessions) {  
        try {  
            // 读出Session个数  
            Integer count = (Integer) ois.readObject();  
            int n = count.intValue();  
            if (log.isDebugEnabled())  
                log.debug("Loading " + n + " persisted sessions");  
            //  读入Session  
            for (int i = 0; i < n; i++) {  
                StandardSession session = getNewSession();  
                session.readObjectData(ois);  
                session.setManager(this);  
                sessions.put(session.getIdInternal(), session);  
                session.activate();  
                sessionCounter++;  
            }  
        } catch (ClassNotFoundException e) {  
            log.error(sm.getString("standardManager.loading.cnfe", e), e);  
            if (ois != null) {  
                try {  
                    ois.close();  
                } catch (IOException f) {  
                    ;  
                }  
                ois = null;  
            }  
            throw e;  
        } catch (IOException e) {  
            log.error(sm.getString("standardManager.loading.ioe", e), e);  
            if (ois != null) {  
                try {  
                    ois.close();  
                } catch (IOException f) {  
                    ;  
                }  
                ois = null;  
            }  
            throw e;  
        } finally {  
            try {  
                if (ois != null)  
                    ois.close();  
            } catch (IOException f) {  
            }  
  
            // 删除Session缓存文件  
            if (file != null && file.exists())  
                file.delete();  
        }  
    }  
  
    if (log.isDebugEnabled())  
        log.debug("Finish: Loading persisted sessions");  
}  

	protected void doLoad() throws ClassNotFoundException, IOException {
		if (log.isDebugEnabled())
			log.debug("Start: Loading persisted sessions");

		// 清空Map
		sessions.clear();

		// 对应work/Catalina/localhost/%app name%/SESSIONS.ser文件
		File file = file();
		if (file == null)
			return;
		if (log.isDebugEnabled())
			log.debug(sm.getString("standardManager.loading", pathname));
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		Loader loader = null;
		ClassLoader classLoader = null;
		try {
			// 载入Session缓存文件
			fis = new FileInputStream(file.getAbsolutePath());
			BufferedInputStream bis = new BufferedInputStream(fis);
			if (container != null)
				loader = container.getLoader();
			if (loader != null)
				classLoader = loader.getClassLoader();
			if (classLoader != null) {
				if (log.isDebugEnabled())
					log.debug("Creating custom object input stream for class loader ");
				ois = new CustomObjectInputStream(bis, classLoader);
			} else {
				if (log.isDebugEnabled())
					log.debug("Creating standard object input stream");
				ois = new ObjectInputStream(bis);
			}
		} catch (FileNotFoundException e) {
			if (log.isDebugEnabled())
				log.debug("No persisted data file found");
			return;
		} catch (IOException e) {
			log.error(sm.getString("standardManager.loading.ioe", e), e);
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException f) {
					;
				}
				ois = null;
			}
			throw e;
		}

		synchronized (sessions) {
			try {
				// 读出Session个数
				Integer count = (Integer) ois.readObject();
				int n = count.intValue();
				if (log.isDebugEnabled())
					log.debug("Loading " + n + " persisted sessions");
				//  读入Session
				for (int i = 0; i < n; i++) {
					StandardSession session = getNewSession();
					session.readObjectData(ois);
					session.setManager(this);
					sessions.put(session.getIdInternal(), session);
					session.activate();
					sessionCounter++;
				}
			} catch (ClassNotFoundException e) {
				log.error(sm.getString("standardManager.loading.cnfe", e), e);
				if (ois != null) {
					try {
						ois.close();
					} catch (IOException f) {
						;
					}
					ois = null;
				}
				throw e;
			} catch (IOException e) {
				log.error(sm.getString("standardManager.loading.ioe", e), e);
				if (ois != null) {
					try {
						ois.close();
					} catch (IOException f) {
						;
					}
					ois = null;
				}
				throw e;
			} finally {
				try {
					if (ois != null)
						ois.close();
				} catch (IOException f) {
				}

				// 删除Session缓存文件
				if (file != null && file.exists())
					file.delete();
			}
		}

		if (log.isDebugEnabled())
			log.debug("Finish: Loading persisted sessions");
	}



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

public Session createSession(String sessionId) {  
    if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) {  
        rejectedSessions++;  
        throw new IllegalStateException(sm.getString("standardManager.createSession.ise"));  
    }  
    return (super.createSession(sessionId));  
}  

	public Session createSession(String sessionId) {
		if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) {
			rejectedSessions++;
			throw new IllegalStateException(sm.getString("standardManager.createSession.ise"));
		}
		return (super.createSession(sessionId));
	}




最后调用到了它的基类的#createSession()方法了。
Java代码
public Session createSession(String sessionId) {  
    // 创建一个新的Session  
    Session session = createEmptySession();  
  
    // 初始化Session的属性  
    session.setNew(true);  
    session.setValid(true);  
    session.setCreationTime(System.currentTimeMillis());  
    session.setMaxInactiveInterval(this.maxInactiveInterval);  
    // 如果Session ID为null,那么就生成一个  
    if (sessionId == null) {  
        sessionId = generateSessionId();  
    }  
    session.setId(sessionId);  
    sessionCounter++;  
  
    return (session);  
  
}  
	public Session createSession(String sessionId) {
		// 创建一个新的Session
		Session session = createEmptySession();

		// 初始化Session的属性
		session.setNew(true);
		session.setValid(true);
		session.setCreationTime(System.currentTimeMillis());
		session.setMaxInactiveInterval(this.maxInactiveInterval);
		// 如果Session ID为null,那么就生成一个
		if (sessionId == null) {
			sessionId = generateSessionId();
		}
		session.setId(sessionId);
		sessionCounter++;

		return (session);

	}



通过上述过程,一个新的Session就创建出来了。
  评论这张
 
阅读(358)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017