Tomcat Session Management mechanism (Tomcat source Analysis VII) _TOMCAT source Analysis Series

Source: Internet
Author: User
Tags session id sessions wrapper

In the previous few we analyzed Tomcat's startup, shutdown, request processing process, Tomcat's classloader mechanism, and this article will then analyze Tomcat's session management aspect content.

Before we start, let's take a look at the overall structure and familiarize ourselves with the overall structure, and then we'll analyze the source code step-by-step. The class diagram of the Tomcat session phase light is as follows:

With the above illustration, we can see that each Standardcontext associates a manager, by default the manager's implementation class is Standardmanager, and Standardmanager internally aggregates multiple sessions. Where standardsession is the default implementation class for the session, When we call Request.getsession, Tomcat returns the Standardsession wrapper by Standardsessionfacade the appearance class.

After the overall structure is clear, let's analyze it further through the source code. We first look at the GetSession method of request.

Org.apache.catalina.connector.request#getsession

Public HttpSession getsession () {sessions session
    = Dogetsession (true);
    if (session = = null) {return
        null;
    }

    return session.getsession ();
}
From the code above, we can see that the first call to the Dogetsession method to get the session, and then call the session's GetSession method to return httpsession, then we'll look at the Dogetsession method:

Org.apache.catalina.connector.request#dogetsession protected Session dogetsession (Boolean create) {//There cannot B
    e a session If no, has been assigned yet if (context = = null) {return (NULL);
        //Return to the current session if it exists and are valid if (session!= null) &&!session.isvalid ()) {
    session = NULL;
    } if (session!= null) {return (session);
    }//Return the requested sessions if it exists and is valid//1 manager manager = NULL;
    If (context!= null) {manager = Context.getmanager ();      } if (manager = = null) {return (NULL); Sessions are not supported}//2 if (Requestedsessionid!= null) {try {sessions = man
        Ager.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 are not committed//3 if (!create) {RE
    Turn (null); The IF (context!= null) && (response!= null) && Context.getservletcontext (). Geteffectivesessi
                Ontrackingmodes (). Contains (Sessiontrackingmode.cookie) && response.getresponse (). iscommitted ()) {throw new illegals
    Tateexception (sm.getstring ("coyoterequest.sessioncreatecommitted")); }//attempt to reuse session ID if one's submitted in a cookie//does not reuse the session ID if it's from
    URL, to prevent possible//phishing attacks//with the SSL session ID if one is present. 4 if (("/". Equals (Context.getsessioncookiepath ()) && Isrequestedsessionidfromcookie ()) | | reque STEDSESSIONSSL) {session = Manager.createSession (Getrequestedsessionid ());
    else {session = Manager.createsession (null);
           }//Creating a new session cookie based the session if (session!= null) && (getcontext ()!= null)
                   && GetContext (). Getservletcontext (). 
        Geteffectivesessiontrackingmodes (). Contains (Sessiontrackingmode.cookie)) {//5 Cookie cookie = Applicationsessioncookieconfig.createsessioncookie (context, session.ge

        Tidinternal (), issecure ());
    Response.addsessioncookieinternal (cookie);
    } if (session = NULL) {return null;
    } session.access ();
return session; }

Here we will focus on the above code labeled the number of places: Callout 1 (line 17th) first from the Standardcontext to get the corresponding Manager object, by default, this place to obtain is actually standardmanager instance. Callout 2 (line 26th) Gets the session from the manager based on Requestedsessionid, and if the session is invalidated, the session is null so that a new session is created below. If the session is not empty, the session's access time is annotated by calling the session's access method, and then returns. Callout 3 (line 43rd) to determine the parameters passed, if False, return null directly, which is actually the case of the corresponding request.getsession (True/false), when the pass false, if there is no session, then directly return empty, Will not be new. Callout 4 (line 59th) calls the manager to create a new session, where default calls to the Standardmanager method, and Standardmanager inherits Managerbase, So the default is actually calling the Managerbase method. Callout 5 (line 72nd) creates a cookie, and the name of the cookie is the familiar jsessionid, and Jsessionid is also configurable, which can be modified by the sessioncookiename of the context node. Like what....

After the session was acquired through Dogetsession, We found that the Session.getsession method was invoked, and the implementation class of the session was standardsession, then we looked at the Standardsession getsession method.

Org.apache.catalina.session.standardsession#getsession public
HttpSession getsession () {

    if (facade = = null) {
        if (securityutil.ispackageprotectionenabled ()) {
            final standardsession fsession = this;
            Façade = accesscontroller.doprivileged (
                    new privilegedaction<standardsessionfacade> () {
                @Override Public
                Standardsessionfacade Run () {return
                    new Standardsessionfacade (fsession);}}
            );
        Else {
            façade = new Standardsessionfacade (this);
        }
    }
    return (façade);

}

Through the above code, we can see through the Standardsessionfacade wrapper class will standardsession after the package return. Here I think you should be familiar with the entire process created by the session.

And then we'll see how the Sesssion was destroyed. In the Tomcat startup process (third of the Tomcat source code reading series), a Containerbackgroundprocessor thread is started after the container is started, which is started when the container is started. This thread invokes the org.apache.catalina.core.containerbase#backgroundprocess periodically through the background, And the Backgroundprocess method will eventually call Org.apache.catalina.session.managerbase#backgroundprocess, Let's take a look at the Backgroundprocess method of manger.

org.apache.catalina.session.managerbase#backgroundprocess public
void Backgroundprocess () {
    count = (count + 1)% Processexpiresfrequency;
    if (count = = 0)
        processexpires ();
}
In the code above, it should be noted that by default backgroundprocess is run every 10 seconds (when Standardengine constructs, the Backgroundprocessordelay is set to 10), And here we control the frequency by processexpiresfrequency, for example, the value of processexpiresfrequency defaults to 6, then the equivalent of not a minute to run the Processexpires method. Next we'll look at Processexpires.

Org.apache.catalina.session.managerbase#processexpires public
void Processexpires () {

    Long timenow = System.currenttimemillis ();
    Session sessions[] = Findsessions ();
    int expirehere = 0;

    if (log.isdebugenabled ())
        log.debug ("Start expire Sessions" + getName () + "at" + TimeNow + "Sessioncount" + Sessio Ns.length);
    for (int i = 0; i < sessions.length i++) {
        if (sessions[i]!=null &&!sessions[i].isvalid ()) {
            Expirehe re++
        }
    }
    Long timeend = System.currenttimemillis ();
    if (log.isdebugenabled ())
         log.debug ("End expire Sessions" + getName () + "Processingtime" + (Timeend-timenow) + " Expired sessions: "+ Expirehere";
    Processingtime + = (timeend-timenow);

}
The above code is relatively simple, first find out the current context of all the session, and then call the session of the IsValid method, next we look at the session of the IsValid method.

Org.apache.catalina.session.standardsession#isvalid Public
Boolean isValid () {

    if (this.expiring) {
        return true;
    }

    if (!this.isvalid) {return
        false;
    }

    if (Activity_check && accesscount.get () > 0) {return
        true;
    }

    if (Maxinactiveinterval > 0) {
        long timenow = System.currenttimemillis ();
        int timeidle;
        if (last_access_at_start) {
            timeidle = (int) (timenow-lastaccessedtime)/1000L);
        } else {
            Timeidle = (i NT) ((timenow-thisaccessedtime)/1000L);
        }
        if (Timeidle >= maxinactiveinterval) {
            expire (true);
        }
    }

    return (this.isvalid);
}

View the above code, mainly by comparing the current time and the last visit is greater than the maximum inactive time interval, if greater than will call expire (true) method to the session for extended processing. It should be noted here that by default Last_access_at_start is False, the reader can also modify the system properties, and if the Last_access_at_start is used, the processing time of the request itself is not counted. For example, a request processing at the beginning of the 10:00, the request processing took 1 minutes, if the Last_access_at_start is true, if the overtime is calculated from 10:00, rather than 10:01.

Next we'll look at the expire method, which reads:

Org.apache.catalina.session.standardsession#expire public void Expire (Boolean notify) {//Check to-if expire is

    In progress or has previously been called if (expiring | |!isvalid) return; Synchronized (this) {//Check again, now we are inside the "Sync so" code only runs once//Double che

        CK locking-expiring and IsValid need to is volatile if (expiring | |!isvalid) return;

        if (manager = = null) return;

        Mark this session as "being expired"//1 expiring = true; Notify interested Application event listeners//Fixme-assumes We call listeners into reverse order Con

        Text context = (context) Manager.getcontainer ();
        The call to expire () may isn't have been triggered by the webapp.
        Make sure the WebApp's class loader is set when calling the//listeners ClassLoader = null; if (Context.getloAder ()!= null && context.getloader (). getClassLoader ()!= null) {OLDTCCL = Thread.cur
            Rentthread (). Getcontextclassloader ();
                        if (globals.is_security_enabled) {privilegedaction<void> pa = new PRIVILEGEDSETTCCL (
                Context.getloader (). getClassLoader ());
            Accesscontroller.doprivileged (PA); else {thread.currentthread (). Setcontextclassloader (Context.getloader (). Getclas
            Sloader ());
            } try {//2 Object listeners[] = Context.getapplicationlifecyclelisteners (); if (notify && (listeners!= null)) {Httpsessionevent event = new H
                Ttpsessionevent (GetSession ());
                    for (int i = 0; i < listeners.length i++) {int J = (listeners.length-1)-I; if (!) ( LISTENERS[J] instanceof HttpSessionlistener)) continue;
                    Httpsessionlistener listener = (httpsessionlistener) listeners[j]; try {context.firecontainerevent ("beforesessiondestroyed", Listene
                        R);
                        Listener.sessiondestroyed (event);
                    Context.firecontainerevent ("aftersessiondestroyed", listener);
                        catch (Throwable t) {exceptionutils.handlethrowable (t);  try {context.firecontainerevent ("aftersessiondestroyed",
                        Listener); catch (Exception e) {//Ignore} manager.ge Tcontainer (). GetLogger (). Error (Sm.getstring ("standardsession.sessionevent"), T); finally {if (OLDTCCL!= null) {if (Globals.is_se)}}}} curity_enabled) {privilegedaction<void> pa = new PRIVILEGEDSETTCCL (Oldt
                    CCL);
                Accesscontroller.doprivileged (PA);
                else {thread.currentthread (). Setcontextclassloader (OLDTCCL);
        }} if (Activity_check) {accesscount.set (0);

        } setvalid (FALSE);

        The Remove this session is active sessions//3 Manager.remove (this, true) in our manager ' s. Notify interested Session event listeners if (Notify) {firesessionevent (session.session_destroyed_
        EVENT, NULL); }//Call to Logout method if (principal instanceof GenericPrincipal) {GenericPrincipal GP
        = (GenericPrincipal) principal;    try {gp.logout (); The catch (Exception e) {Manager.getcontainer (). GetLogger (). Error (Sm.getstring ("St
            Andardsession.logoutfail "), e);

        }//We have completed expire of this session expiring = false;
        Unbind any objects associated with this session//4 String keys[] = keys ();

    for (int i = 0; i < keys.length i++) removeattributeinternal (Keys[i], notify); }

}

The main stream of the above code I have marked the number, we have to analyze each: Callout 1 (line 18th) to mark the current session for extended callout 2 (line 41st) to start Httpsessionlistener listener method. Callout 3 (line 89th) removes the current session Callout 4 (line 113th) from the manager and removes the property that is saved in the session.

Here we have already known the process of creating and destroying the Standardsession in Tomcat, and in fact Standardsession is only implementing memory session storage, and Tomcat is also supporting the persistence of Session and synchronization between the session cluster nodes. We'll analyze the content later.






Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.