tomcat 7 下 session 的实现详解

session 是记录服务器会话的一个对象,他可以跟踪用户从登陆到关闭浏览器一系列动作,具体的创建代码

 

public void addSession(HttpServletRequest request,String key,String value){
		HttpSession session = request.getSession();
		session.setAttribute(key, value);
	}

 

 

通过 HttpServletRequest 对象获取session 对象, 对应的tomcat 下的org.apache.catalina.connector.RequestFacade 的 getSession()方法 

 

 @Override
    public HttpSession getSession() {

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

        return getSession(true);
    }

     调用 getSession(create) 方法

 

 

   @Override
    //create 参数就是是否创建session 如果false,服务器中不存在对应的session,则返回null 
    public HttpSession getSession(boolean create) {

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

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

   将获取session转交给org.apache.catalina.connector.Request 类处理,RequestFacade  是Request 类的一个门面类,他包装了Request 的方法调用,对外开放,隐藏了Request 的实现细节,

 

调用了 Request 类的getSession(create) 方法

 

@Override
      
	public HttpSession getSession(boolean create) {
               //处理获取session
		Session session = doGetSession(create);
		if (session == null) {
			return null;
		}

		return session.getSession();
	}

 

 

    Session session = doGetSession(create);  这个session 是tomcat的session 接口,不是 java.javax 下的。

 

protected Session doGetSession(boolean create) {

		// There cannot be a session if no context has been assigned yet
		if (context == null) {
			return (null);
		}

		// Return the current session if it exists and is valid
		if ((session != null) && !session.isValid()) {
			session = null;
		}
		if (session != null) {
			return (session);
		}

		// Return the requested session if it exists and is valid
		Manager manager = null;
		if (context != null) {
			manager = context.getManager();
		}
		if (manager == null) {
			return (null); // Sessions are not supported
		}
               //如果cookie 中的jsessionId ,或者是URL paramaters不为空,
                 // 通过manager 管理器查找session

 

		if (requestedSessionId != null) {
			try {
				session = manager.findSession(requestedSessionId);
			} catch (IOException e) {
				session = null;
			}
			if ((session != null) && !session.isValid()) {
				session = null;
			}
			if (session != null) {
				session.access();
				return (session);
			}
		}

		// Create a new session if requested and the response is not committed
		if (!create) {
			return (null);
		}
		if ((context != null)
				&& (response != null)
				&& context.getServletContext()
						.getEffectiveSessionTrackingModes()
						.contains(SessionTrackingMode.COOKIE)
				&& response.getResponse().isCommitted()) {
			throw new IllegalStateException(
				sm.getString("coyoteRequest.sessionCreateCommitted"));
		}

		// Attempt to reuse session id if one was submitted in a cookie
		// Do not reuse the session id if it is from a URL, to prevent possible
		// phishing attacks
		// Use the SSL session ID if one is present.
		if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie())
				|| requestedSessionSSL) {
			session = manager.createSession(getRequestedSessionId());
		} else {
			session = manager.createSession(null);
		}

		// Creating a new session cookie based on that session
		if ((session != null)
				&& (getContext() != null)
				&& getContext().getServletContext()
						.getEffectiveSessionTrackingModes()
						.contains(SessionTrackingMode.COOKIE)) {
			Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(
				context, session.getIdInternal(), isSecure());

			response.addSessionCookieInternal(cookie);
		}

		if (session == null) {
			return null;
		}

		session.access();
		return session;
	}

   其中requestedSessionId 是 org.apache.catalina.connector.CoyoteAdapter 下的postParseRequest方法解析的,具体代码片段

           // Now we have the context, we can parse the session ID from the URL
            // (if any). Need to do this before we redirect in case we need to
            // include the session id in the redirect
            String sessionID = null;
            if (request.getServletContext().getEffectiveSessionTrackingModes()
                    .contains(SessionTrackingMode.URL)) {

                // Get the session ID if there was one
                sessionID = request.getPathParameter(
                        SessionConfig.getSessionUriParamName(
                                request.getContext()));
                if (sessionID != null) {
                    request.setRequestedSessionId(sessionID);
                    request.setRequestedSessionURL(true);
                }
            }

            // Look for session ID in cookies and SSL session
            parseSessionCookiesId(req, request);
            parseSessionSslId(request);

            sessionID = request.getRequestedSessionId();

 

    对session 的管理 是Manager 接口, org.apache.catalina 包下的。具体是实现类 是ManagerBase

 

  //如果cookie 中的jsessionId ,或者是URL paramaters不为空,通过manager 管理器查找session
		if (requestedSessionId != null) {
			try {
				session = manager.findSession(requestedSessionId);
			} catch (IOException e) {
				session = null;
			}
			if ((session != null) && !session.isValid()) {
				session = null;
			}
			if (session != null) {
				session.access();
				return (session);
			}
		}

    对应ManagerBase 类中的

 

 

   @Override
    public Session findSession(String id) throws IOException {

        if (id == null)
            return (null);
        return sessions.get(id);

    }

     sessions 是ManagerBase 对象的一个属性,

 

  protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

用并发的HashMap 来存放session信息,其中Key 值就是cookie 中对应的jsessionId,如果找到就返回找到的session 对象,如果没有找到并且create 参数是false ,表示不创建session 则 返回null,如果是true 就是创建session 对象,具体的创建session 对象的代码片段为:

 

 //判断cookie 中是否有jsessionId 如果有,就使用这个jsessionId ,如果没有就创建新的jsessionId
if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie())
				|| requestedSessionSSL) {
			session = manager.createSession(getRequestedSessionId());
		} else {
			session = manager.createSession(null);
		}

                //创建一个新的session cookie,基于刚刚创建好的session
		if ((session != null)
				&& (getContext() != null)
				&& getContext().getServletContext()
						.getEffectiveSessionTrackingModes()
						.contains(SessionTrackingMode.COOKIE)) {
			Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(
				context, session.getIdInternal(), isSecure());

			response.addSessionCookieInternal(cookie);
		}

  关于session 中 cookie name 值默认是JSESSIONID ,如果在web.xml 中配置了session-config ,其中cookie-config 下的name 就是sessionCookieName 值,如果没有配置的话,就是默认

 具体代码如下:

  public static String getSessionCookieName(Context context) {

        String result = getConfiguredSessionCookieName(context);

        if (result == null) {
            result = DEFAULT_SESSION_COOKIE_NAME;
        }

        return result;
    }

   

具体创建session 的逻辑在ManagerBase 中 

 public Session createSession(String sessionId) {
        
        if ((maxActiveSessions >= 0) &&
                (getActiveSessions() >= maxActiveSessions)) {
            rejectedSessions++;
            throw new TooManyActiveSessionsException(
                    sm.getString("managerBase.createSession.ise"),
                    maxActiveSessions);
        }
        
        //创建一个空的session ,其实就是创建org.apache.catalina.session.StandardSession 对象,将该对象交由manager 管理
        Session session = createEmptySession();

        // Initialize the properties of the new session and return it
        session.setNew(true);
        session.setValid(true);
        session.setCreationTime(System.currentTimeMillis());
        session.setMaxInactiveInterval(this.maxInactiveInterval);
        String id = sessionId;
        if (id == null) {
            //生成sessionId,具体的生成SessionId 的逻辑在org.apache.catalina.util.SessionIdGenerator
    下的generateSessionId 方法,
            id = generateSessionId();
        }
        session.setId(id);
        sessionCounter++;

        SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
        synchronized (sessionCreationTiming) {
            sessionCreationTiming.add(timing);
            sessionCreationTiming.poll();
        }
        return (session);

    }
    

   以上就是创建HttpSession 的过程, 都是个人的理解,由于个人水平有限,还有很多地方没有讲清楚或者说错了,例如session 的持久化技术,具体可以参考 org.apache.catalina.session.StoreBase ,tomcat 提供两种持久化机制,分布是文件持久化,和jdbc 数据持久化 对应的类是FileStore,JDBCStore

 

猜你喜欢

转载自lliang54.iteye.com/blog/2394716
今日推荐