读书人

Tomcat源码-Session的分析1

发布时间: 2012-10-10 13:58:11 作者: rapoo

Tomcat源码---Session的分析一

一,前面看了大致的tomcat的请求/响应,接下来的文章对tomcat里面的一些模块进行详细分析,从中学习其思想...

?

Session的功能(Session?对象可以存储特定用户会话所需的信息):

??1,session是一个以bean的形式存在的,存储在内存中,特定用户可对其进行crud操作.

??2,session是有生命周期的.

??3,sesson是通过特定用户访问系统时,返回给一个jsessionid来进行识别用户的

----------------------------------------------

1,当客户端发送请求时,如果在头部文件中有传送jsessionid(生成jsessionid是在下面一部分讲),则执行以下步骤

执行到请求时会执行这个方法CoyoteAdapter#service...方法下的这步时if (postParseRequest(req, request, res, response))?

对sessionid进行了操作,如下:

?

    /**     * Parse additional request parameters.     */    protected boolean postParseRequest(org.apache.coyote.Request req,                                        Request request,                           org.apache.coyote.Response res,                                        Response response)            throws Exception {        //代码略            // Parse session Id(解析;url=;jsessionid=)        parseSessionId(req, request);       //代码略               // Parse session Id(解决cookie中所带的jsessionid=)        parseSessionCookiesId(req, request);        return true;    }

?

?? 1,parseSessiond(req,request)

??? /**

     * Parse session id in URL.     */    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            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));                // Extract session ID from request URI                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);            }            //如果有jsessionid,设置到request中            request.setRequestedSessionURL(true);        } else {            request.setRequestedSessionId(null);            request.setRequestedSessionURL(false);        }    }

??2,parseSessionCookiesId(req, request);

?

 /**     * Parse session id in cookie     */    protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {        // If session tracking via cookies has been disabled for the current        // context, don't go looking for a session ID in a cookie as a cookie        // from a parent context with a session ID may be present which would        // overwrite the valid session ID encoded in the URL        Context context = (Context) request.getMappingData().context;        if (context != null && !context.getCookies())            return;        // Parse session id from cookies        //获取cookies        Cookies serverCookies = req.getCookies();        int count = serverCookies.getCookieCount();        if (count <= 0)            return;        for (int i = 0; i < count; i++) {            ServerCookie scookie = serverCookies.getCookie(i);            if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {                // Override anything requested in the URL                if (!request.isRequestedSessionIdFromCookie()) {                    // Accept only the first session id cookie                    convertMB(scookie.getValue());                    request.setRequestedSessionId                        (scookie.getValue().toString());                    request.setRequestedSessionCookie(true);                    request.setRequestedSessionURL(false);                    if (log.isDebugEnabled())                        log.debug(" Requested cookie session id is " +                            request.getRequestedSessionId());                } else {                    if (!request.isRequestedSessionIdValid()) {                        // Replace the session id until one is valid                        convertMB(scookie.getValue());                        //在进行查找jsessionid如果有的话,设置进request                        request.setRequestedSessionId                            (scookie.getValue().toString());                    }                }            }        }    }

?

由以上可知如果客户端有访问过系统的话,客户端的jsessionid将被设置进request中

??----------------------------------------------------

在StandardManager是用来管理Session类的,首先是StandardManager的实例化是在

StandardContext#start

?

  // Acquire clustered manager                Manager contextManager = null;                if (manager == null) {                    if ( (getCluster() != null) && distributable) {                        try {                            contextManager = getCluster().createManager(getName());                        } catch (Exception ex) {                            log.error("standardContext.clusterFail", ex);                            ok = false;                        }                    } else {                        contextManager = new StandardManager();                    }                }                 

-------------------------------------------

?现在查看的是Session的生成过程..request.getSession()

?

  /**     * Return the session associated with this Request, creating one     * if necessary.     */    public HttpSession getSession() {        Session session = doGetSession(true);        if (session != null) {            return session.getSession();        } else {            return null;        }    }

?

?doGetSession(true)

?

 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        //StandardContext#start时进行的初始化        Manager manager = null;        if (context != null)            manager = context.getManager();        if (manager == null)            return (null);      // Sessions are not supported        if (requestedSessionId != null) {            try {                 //不为空的话,进行查找                session = manager.findSession(requestedSessionId);            } catch (IOException e) {                session = null;            }            if ((session != null) && !session.isValid())                session = null;            if (session != null) {                //更新时间,使其生命周期重设为30(默认)                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.getCookies() &&            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        //判断session cookie的存储路径        if (connector.getEmptySessionPath()                 && isRequestedSessionIdFromCookie()) {            //进行创建            session = manager.createSession(getRequestedSessionId());        } else {            session = manager.createSession(null);        }        // Creating a new session cookie based on that session        if ((session != null) && (getContext() != null)               && getContext().getCookies()) {            Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,                                       session.getIdInternal());            configureSessionCookie(cookie);            //在响应时,返回session cookie,这样在客户端就接收到一个jsessionid            response.addCookieInternal(cookie, context.getUseHttpOnly());        }        if (session != null) {            //如上            session.access();            return (session);        } else {            return (null);        }    }
?

?

?由上面的代码可以看出,sesion是先查找再创建,,,

ManagerBase#findSession

?

  public Session findSession(String id) throws IOException {        if (id == null)            return (null);      //sessions(ConcurrentHashMap<String, Session>)进行读取        return (Session) sessions.get(id);    }

?#createSession

?

    public Session createSession(String sessionId) {                // Recycle or create a Session instance        //进行创建        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);        if (sessionId == null) {          //产生一个jsessionid            sessionId = generateSessionId();        // FIXME WHy we need no duplication check?        /*                      synchronized (sessions) {                while (sessions.get(sessionId) != null) { // Guarantee                    // uniqueness                    duplicates++;                    //产生一个jsessionid                    sessionId = generateSessionId();                }            }        */                        // FIXME: Code to be used in case route replacement is needed            /*        } else {            String jvmRoute = getJvmRoute();            if (getJvmRoute() != null) {                String requestJvmRoute = null;                int index = sessionId.indexOf(".");                if (index > 0) {                    requestJvmRoute = sessionId                            .substring(index + 1, sessionId.length());                }                if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) {                    sessionId = sessionId.substring(0, index) + "." + jvmRoute;                }            }            */        }        session.setId(sessionId);        sessionCounter++;        return (session);

?故一整个流程是:

?当客户端有请求session时request.getSession(),并生成一个jsessionid cookie返回给客户端,以后每次访问都得带着这个jsessionid过来,进行对ConcurrentHashMap<String, Session>进行识别.

------------------------------------------

还有一个问题就是当服务器突然中断掉时,重新启动时,未过期的session是可以重新加载的...

StandardManager#start()方法。最后调用了#load()方法.

?

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()

?

 protected void doLoad() throws ClassNotFoundException, IOException {        if (log.isDebugEnabled())            log.debug("Start: Loading persisted sessions");        // Initialize our internal data structures        sessions.clear();        // Open an input stream to the specified pathname, if any       // %CATALINA_HOME%/localhost/%app_name% /SESSIONS.ser文件,每一个应用下都有这个sessions.ser       //可以从这里还原未过期的session        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 {            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;        }        // Load the previously unloaded active sessions        synchronized (sessions) {            try {                Integer count = (Integer) ois.readObject();                int n = count.intValue();                if (log.isDebugEnabled())                    log.debug("Loading " + n + " persisted sessions");                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 {                // Close the input stream                try {                    if (ois != null)                        ois.close();                } catch (IOException f) {                    // ignored                }                // Delete the persistent storage file                if (file != null && file.exists() )                    file.delete();            }        }        if (log.isDebugEnabled())            log.debug("Finish: Loading persisted sessions");    }
?

?

?

?

?

读书人网 >软件架构设计

热点推荐