高防服务器

Tomcat9中如何管理session


Tomcat9中如何管理session

发布时间:2021-12-08 17:51:05 来源:高防服务器网 阅读:82 作者:小新 栏目:编程语言

这篇文章主要介绍Tomcat9中如何管理session,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

源码解析

session相关共有两个类:

  • StandardSession:默认的session的类,是对session的系统抽象

  • StandardManager:默认的session管理类,管理session的创建、加载、持久化等

    org.apache.catalina.core.StandardContext.startInternal()
protected synchronized void startInternal() throws LifecycleException {  ...省略其他代码...                  Manager contextManager = null;                  Manager manager = getManager();                  if (manager == null) {                      if (log.isDebugEnabled()) {                          log.debug(sm.getString("standardContext.cluster.noManager",                                  Boolean.valueOf((getCluster() != null)),                                  Boolean.valueOf(distributable)));                      }                      if ((getCluster() != null) && distributable) {                          try {                              contextManager = getCluster().createManager(getName());                          } catch (Exception ex) {                              log.error(sm.getString("standardContext.cluster.managerError"), ex);                              ok = false;                          }                      } else {                          contextManager = new StandardManager();                      }                  }                 // Configure default manager if none was specified                  if (contextManager != null) {                      if (log.isDebugEnabled()) {                          log.debug(sm.getString("standardContext.manager",                                  contextManager.getClass().getName()));                      }                      setManager(contextManager);                  }  ...省略其他代码...  public void setManager(Manager manager) {          Lock writeLock = managerLock.writeLock();          writeLock.lock();          Manager oldManager = null;          try {              // Change components if necessary              oldManager = this.manager;              if (oldManager == manager)                  return;              this.manager = manager;              // Stop the old component if necessary              if (oldManager instanceof Lifecycle) {                  try {                      ((Lifecycle) oldManager).stop();                      ((Lifecycle) oldManager).destroy();                  } catch (LifecycleException e) {                      log.error(sm.getString("standardContext.setManager.stop"), e);                  }              }              // Start the new component if necessary              if (manager != null) {                  manager.setContext(this);              }              if (getState().isAvailable() && manager instanceof Lifecycle) {                  try {                      ((Lifecycle) manager).start();                  } catch (LifecycleException e) {                      log.error(sm.getString("standardContext.setManager.start"), e);                  }              }          } finally {              writeLock.unlock();          }          // Report this property change to interested listeners          support.firePropertyChange("manager", oldManager, manager);      }  }

在StandardContext的start方法中,会对sessionManager进行实例化,这里是支持Tomcat的集群session,本文以单机session管理为例,即StandardManager,在setManager中会调用StandardManager.start

org.apache.catalina.session.StandardManager.start()
 protected synchronized void startInternal() throws LifecycleException {          super.startInternal();          // Load unloaded sessions, if any          try {              load();          } catch (Throwable t) {              ExceptionUtils.handleThrowable(t);              log.error(sm.getString("standardManager.managerLoad"), t);          }          setState(LifecycleState.STARTING);      }  protected String pathname = "SESSIONS.ser";  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          File file = file();          if (file == null) {              return;          }          if (log.isDebugEnabled()) {              log.debug(sm.getString("standardManager.loading", pathname));          }          Loader loader = null;          ClassLoader classLoader = null;          Log logger = null;          try (FileInputStream fis = new FileInputStream(file.getAbsolutePath());                  BufferedInputStream bis = new BufferedInputStream(fis)) {              Context c = getContext();              loader = c.getLoader();              logger = c.getLogger();              if (loader != null) {                  classLoader = loader.getClassLoader();              }              if (classLoader == null) {                  classLoader = getClass().getClassLoader();              }              // Load the previously unloaded active sessions              synchronized (sessions) {                  try (ObjectInputStream ois = new CustomObjectInputStream(bis, classLoader, logger,                          getSessionAttributeValueClassNamePattern(),                          getWarnOnSessionAttributeFilterFailure())) {                      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();                          if (!session.isValidInternal()) {                              // If session is already invalid,                              // expire session to prevent memory leak.                              session.setValid(true);                              session.expire();                          }                          sessionCounter++;                      }                  } finally {                      // Delete the persistent storage file                      if (file.exists()) {                          if (!file.delete()) {                              log.warn(sm.getString("standardManager.deletePersistedFileFail", file));                          }                      }                  }              }          } catch (FileNotFoundException e) {              if (log.isDebugEnabled()) {                  log.debug("No persisted data file found");              }              return;          }          if (log.isDebugEnabled()) {              log.debug("Finish: Loading persisted sessions");          }      }  protected void doUnload() throws IOException {          if (log.isDebugEnabled())              log.debug(sm.getString("standardManager.unloading.debug"));          if (sessions.isEmpty()) {              log.debug(sm.getString("standardManager.unloading.nosessions"));              return; // nothing to do          }          // Open an output stream to the specified pathname, if any          File file = file();          if (file == null) {              return;          }          if (log.isDebugEnabled()) {              log.debug(sm.getString("standardManager.unloading", pathname));          }          // Keep a note of sessions that are expired          List<StandardSession> list = new ArrayList<>();          try (FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());                  BufferedOutputStream bos = new BufferedOutputStream(fos);                  ObjectOutputStream oos = new ObjectOutputStream(bos)) {              synchronized (sessions) {                  if (log.isDebugEnabled()) {                      log.debug("Unloading " + sessions.size() + " sessions");                  }                  // Write the number of active sessions, followed by the details                  oos.writeObject(Integer.valueOf(sessions.size()));                  for (Session s : sessions.values()) {                      StandardSession session = (StandardSession) s;                      list.add(session);                      session.passivate();                      session.writeObjectData(oos);                  }              }          }          // Expire all the sessions we just wrote          if (log.isDebugEnabled()) {              log.debug("Expiring " + list.size() + " persisted sessions");          }          for (StandardSession session : list) {              try {                  session.expire(false);              } catch (Throwable t) {                  ExceptionUtils.handleThrowable(t);              } finally {                  session.recycle();              }          }          if (log.isDebugEnabled()) {              log.debug("Unloading complete");          }      }

在start方法中,会调用load方法,load方法最终调用doLoad方法,会读取文件名为SESSIONS.ser的文件,该文件存储了Tomcat关闭时session的内容,具体存储逻辑在doUnload方法中

Request.getSession()
public HttpSession getSession() {          Session session = doGetSession(true);          if (session == null) {              return null;          }          return session.getSession();      }  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;          }          // Return the requested session if it exists and is valid          Manager manager = context.getManager();          if (manager == null) {              return null;      // Sessions are not supported          }          if (requestedSessionId != null) {              try {                  session = manager.findSession(requestedSessionId); //读取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;          }          boolean trackModesIncludesCookie =                  context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE);          if (trackModesIncludesCookie && response.getResponse().isCommitted()) {              throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));          }          String sessionId = getRequestedSessionId();          if (requestedSessionSSL) {              // If the session ID has been obtained from the SSL handshake then              // use it.          } else if (("/".equals(context.getSessionCookiePath())                  && isRequestedSessionIdFromCookie())) {              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); //创建新的session          // Creating a new session cookie based on that session          if (session != null && trackModesIncludesCookie) {              Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(                      context, session.getIdInternal(), isSecure());              response.addSessionCookieInternal(cookie);          }          if (session == null) {              return null;          }          session.access();          return session;      }

在getSession方法中,会先根据sessionId在调用manager.findSession查找,如果查找不存在则会调用manager.createSession创建

findSession() & createSession()
public Session findSession(String id) throws IOException {          if (id == null) {              return null;          }          return sessions.get(id);      }  public Session createSession(String sessionId) {          if ((maxActiveSessions >= 0) &&                  (getActiveSessions() >= maxActiveSessions)) {              rejectedSessions++;              throw new TooManyActiveSessionsException(                      sm.getString("managerBase.createSession.ise"),                      maxActiveSessions);          }          // 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(getContext().getSessionTimeout() * 60);          String id = sessionId;          if (id == null) {              id = generateSessionId();          }          session.setId(id);          sessionCounter++;          SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);          synchronized (sessionCreationTiming) {              sessionCreationTiming.add(timing);              sessionCreationTiming.poll();          }          return session;      }

所有的session为维护在一个HashMap中,在创建时会想Map中维护,读取是从Map中查找。

以上是“Tomcat9中如何管理session”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注高防服务器网行业资讯频道!

[微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
[