org.apache.catalina.connector.Request的getSession方法说起

 public HttpSession getSession() {
        Session session = doGetSession(true);//如果没有找到session默认情况下创建新session
        if (session == null) {
            return null;
        }

        return session.getSession();//这里返回一个StandardSessionFacade对象,主要是因为StandardSession不仅实现了HttpSession还实现了Session接口,如果返回StandardSession对象,那就有可能被用户使用session接口中的方法,为了避免这种情况,为了安全,就返回StandardSessionFacade,他只实现了HttpSession接口。

    }

protected Session doGetSession(boolean create) {

        // There cannot be a session if no context has been assigned yet
        Context context = getContext();
        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);//估计使用了forward方法,导致重复使用了request
        }

        // Return the requested session if it exists and is valid
        Manager manager = context.getManager();//返回session管理器
        if (manager == null) {
            return null;        // Sessions are not supported
        }
        if (requestedSessionId != null) {//不为null说明http请求报文头中带有sessionID
            try {
                session = manager.findSession(requestedSessionId);//在manager管理的sessions(ConcurrentHashMap)中根据sessionid查找session对象

            } 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 ((response != null) &&
            context.getServletContext().getEffectiveSessionTrackingModes().
                    contains(SessionTrackingMode.COOKIE) &&
            response.getResponse().isCommitted()) {//没看懂为啥,估计是因为response已经输出,不能再获取request的session了。
            throw new IllegalStateException
              (sm.getString("coyoteRequest.sessionCreateCommitted"));
        }

        // Re-use session IDs provided by the client in very limited
        // circumstances.
        String sessionId = getRequestedSessionId();
        if (requestedSessionSSL) {
            // If the session ID has been obtained from the SSL handshake then
            // use it.
        } else if (("/".equals(context.getSessionCookiePath())//这种情况是cookie在同一个host下多个应用程序都可见
                && isRequestedSessionIdFromCookie())) {
            /* This is the common(ish) use case: using the same session ID with
             * multiple web applications on the same host. Typically this is
             * used by Portlet implementations. It only works if sessions are
             * tracked via cookies. The cookie must have a path of "/" else it
             * won't be provided for requests to all web applications.
             *
             * Any session ID provided by the client should be for a session
             * that already exists somewhere on the host. Check if the context
             * is configured for this to be confirmed.
             */
            if (context.getValidateClientProvidedNewSessionId()) {
                boolean found = false;
                for (Container container : getHost().findChildren()) {
                    Manager m = ((Context) container).getManager();
                    if (m != null) {
                        try {
                            if (m.findSession(sessionId) != null) {
                                found = true;
                                break;
                            }
                        } catch (IOException e) {
                            // Ignore. Problems with this manager will be
                            // handled elsewhere.
                        }
                    }
                }
                if (!found) {
                    sessionId = null;
                }
            }
        } else {
            sessionId = null;
        }
        session = manager.createSession(sessionId);

        // 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;
    }


至于session的持久化是由线程完成的,这个线程不仅会持久化session,还会实现热加载,如下:

ContainerBase.threadStart

 protected void threadStart() {

        if (thread != null)
            return;
        if (backgroundProcessorDelay <= 0) //从代码来看只有StandardEngine给他赋值为10,所以只有StandardEngine这个container能往下执行,所以本来是一个container一个线程,现在来看只有StandardEngine能往下走,所以就这一个线程了,不过已经足够了。

            return;

        threadDone = false;
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
        thread.setDaemon(true);
        thread.start();

    }

略去一下代码后 会调用到container.backgroundProcess();

有些container比如context和wrapper里有自己的backgroundProcess,有的没有自己的,就用ContainerBase中的

public void backgroundProcess() {
        
        if (!getState().isAvailable())
            return;

        if (cluster != null) {
            try {
                cluster.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
            }
        }
        if (loader != null) {
            try {
                loader.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
            }
        }
        if (manager != null) {
            try {
                manager.backgroundProcess();//这里就是持久化session的代码,但后续还会需要判断一下条件来决定是否持久化session,比如maxIdleBackup

            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
            }
        }
        Realm realm = getRealmInternal();
        if (realm != null) {
            try {
                realm.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
            }
        }
        Valve current = pipeline.getFirst();
        while (current != null) {
            try {
                current.backgroundProcess();
            } catch (Exception e) {
                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
            }
            current = current.getNext();
        }
        fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
    }