成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Tomcat的session管理探究

rollback / 1408人閱讀

摘要:下面是源代碼片段的調(diào)用鏈?zhǔn)沁@樣的里有一個(gè)線程實(shí)例,這個(gè)線程會(huì)每隔的時(shí)間調(diào)用,這個(gè)方法調(diào)用,這個(gè)方法調(diào)用,這個(gè)方法調(diào)用,在這里清理掉已經(jīng)過(guò)期的。下面是源代碼片段的值會(huì)作為新的默認(rèn)的值實(shí)際上用戶在到后修改這個(gè)值。

我有一個(gè)項(xiàng)目需要模擬HttpSession,在參考Tomcat的HttpSession管理時(shí)有一點(diǎn)心得,在這里記錄一下。

先說(shuō)說(shuō)這幾個(gè)關(guān)鍵類(lèi):

org.apache.catalina.session.StandardManager: 管理Session的類(lèi)

org.apache.catalina.session.StandardSession: HttpSession的實(shí)現(xiàn)

org.apache.catalina.connector.Request: HttpServletRequest的實(shí)現(xiàn)

StandardManager

下面介紹一下和Session相關(guān)的幾個(gè)關(guān)鍵屬性,以及方法

processExpiresFrequency

每隔多少次StandardManager.backgroundProcess做一次session清理,數(shù)字越小越頻繁,默認(rèn)6次。

下面是源代碼片段:

/**
  * Frequency of the session expiration, and related manager operations.
  * Manager operations will be done once for the specified amount of
  * backgrondProcess calls (ie, the lower the amount, the most often the
  * checks will occur).
  */
protected int processExpiresFrequency = 6;

StandardManager.backgroundProcess的調(diào)用鏈?zhǔn)沁@樣的:

ContainerBase里有一個(gè)ContainerBackgroundProcessor線程實(shí)例,
這個(gè)線程會(huì)每隔ContainerBase.backgroundProcessorDelay的時(shí)間調(diào)用-->

ContainerBase.processChildren,這個(gè)方法調(diào)用-->

ContainerBase.backgroundProcess,這個(gè)方法調(diào)用-->

StandardManager.backgroundProcess,這個(gè)方法調(diào)用-->

StandardManager.processExpires,在這里清理掉已經(jīng)過(guò)期的Session。

maxInactiveInterval

一個(gè)session不被訪問(wèn)的時(shí)間間隔,默認(rèn)30分鐘(1800秒)。

下面是源代碼片段:

/**
  * The default maximum inactive interval for Sessions created by
  * this Manager.
  */
protected int maxInactiveInterval = 30 * 60;

StandardManager.maxInactiveInterval的值會(huì)作為新Session的默認(rèn)maxInactiveInterval的值
(實(shí)際上用戶在get到session后修改這個(gè)值)。

下面是代碼片段:

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

  // ...
}
StandardSession access()

StandardSession.access方法是用來(lái)設(shè)置這個(gè)Session被訪問(wèn)的時(shí)間的,何時(shí)被調(diào)用會(huì)在Request里講。

下面是代碼片段:

/**
* Update the accessed time information for this session.  This method
* should be called by the context when a request comes in for a particular
* session, even if the application does not reference it.
*/
@Override
public void access() {

  this.thisAccessedTime = System.currentTimeMillis();

  if (ACTIVITY_CHECK) {
    accessCount.incrementAndGet();
  }

}
endAccess()

StandardSession.endAccess方法是用來(lái)設(shè)置這個(gè)Session訪問(wèn)結(jié)束的時(shí)間的,何時(shí)被調(diào)用會(huì)在Request里講。

/**
* End the access.
*/
@Override
public void endAccess() {

  isNew = false;

  /**
  * The servlet spec mandates to ignore request handling time
  * in lastAccessedTime.
  */
  if (LAST_ACCESS_AT_START) {
    this.lastAccessedTime = this.thisAccessedTime;
    this.thisAccessedTime = System.currentTimeMillis();
  } else {
    this.thisAccessedTime = System.currentTimeMillis();
    this.lastAccessedTime = this.thisAccessedTime;
  }

  if (ACTIVITY_CHECK) {
    accessCount.decrementAndGet();
  }

}
isValid()

StandardSession.isValid方法是很關(guān)鍵的,這個(gè)方法會(huì)用來(lái)判斷這個(gè)Session是否還處于有效狀態(tài)。

代碼片段:

/**
* Return the isValid flag for this session.
*/
@Override
public boolean isValid() {

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

  if (this.expiring) {
    return true;
  }

  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 = (int) ((timeNow - thisAccessedTime) / 1000L);
    }
    if (timeIdle >= maxInactiveInterval) {
      expire(true);
    }
  }

  return this.isValid;
}

ACTIVITY_CHECK,的意思是判斷session是否過(guò)期前,是否要先判斷一下這個(gè)session是否還在使用中(用accessCount判斷)

如果是,那么這個(gè)session是不會(huì)過(guò)期的。

如果不是,那么這個(gè)session就會(huì)被“粗暴”地過(guò)期。

LAST_ACCESS_AT_START,是兩種判斷session過(guò)期方式的開(kāi)關(guān)

如果為true,會(huì)根據(jù)getSession的時(shí)間判斷是否過(guò)期了。access()endAccess()之間的時(shí)間是不算進(jìn)去的。

如果為false,則根據(jù)session結(jié)束訪問(wèn)的時(shí)間判斷是否過(guò)期了。access()endAccess()之間的時(shí)間是算進(jìn)去的。

Request doGetSession()

這個(gè)方法是tomcat獲得session的地方,從下面的代碼判斷里可以看到,它會(huì)調(diào)用StandardSession.access()方法:

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
  }
  if (requestedSessionId != null) {
    try {
      session = manager.findSession(requestedSessionId);
    } catch (IOException e) {
      session = null;
    }
    if ((session != null) && !session.isValid()) {
      session = null;
    }
    if (session != null) {
      // 在這里調(diào)用了access
      session.access();
      return (session);
    }
  }
  // ...  
}
recycle()

這個(gè)當(dāng)一個(gè)請(qǐng)求處理完畢后,CoyoteAdapter會(huì)調(diào)用Request.recycle()方法,
而這個(gè)方法會(huì)調(diào)用StandardSession.endAccess()方法(也就是告訴Session,你的這次訪問(wèn)結(jié)束了)

/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {

  // ...  
  if (session != null) {
    try {
      session.endAccess();
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t);
    }
  }
  // ...

}

所以,當(dāng)用戶調(diào)用HttpSession.getSession()方法時(shí),發(fā)生了這些事情:

Request.doGetSession()

StandardSession.access()

返回給用戶Session

用戶在Servlet里處理完請(qǐng)求

Request.recycle()

StandardSession.endAccess()

陷阱

從上面的流程可以看出Tomcat假設(shè)在Request的生命周期結(jié)束之后便不會(huì)有人再去訪問(wèn)Session了。

但是如果我們?cè)谔幚鞷equest的Thread A里另起一個(gè)Thread B,并且在Thread B里訪問(wèn)Session時(shí)會(huì)怎樣呢?

你可能已經(jīng)猜到,可能會(huì)訪問(wèn)到一個(gè)已經(jīng)過(guò)期的Session。下面是一個(gè)小小的測(cè)試代碼:

https://gist.github.com/chanjarster/e1793251477cbabfbe92

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64926.html

相關(guān)文章

  • Nginx+Tomcat關(guān)于Session管理

    摘要:前言對(duì)的管理一直有了解,但是一直沒(méi)有實(shí)際操作一遍,本文從最簡(jiǎn)單的安裝啟動(dòng)開(kāi)始,通過(guò)實(shí)例的方式循序漸進(jìn)的介紹了幾種管理的方式。 前言 Nginx+Tomcat對(duì)Session的管理一直有了解,但是一直沒(méi)有實(shí)際操作一遍,本文從最簡(jiǎn)單的安裝啟動(dòng)開(kāi)始,通過(guò)實(shí)例的方式循序漸進(jìn)的介紹了幾種管理session的方式。 nginx安裝配置 1.安裝nginx [root@localhost ~]# y...

    superw 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<