论坛首页 Java企业应用论坛

最近在研究tomcat的session管理,遇到以下问题请大家帮忙看看

浏览 4287 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-09-20   最后修改:2012-09-20
以下这两个都是StandardSession中的
session.isValid()//判断当前session对象是否还有效
session.expiring //是否过期

因为项目需要判断当前session是否有效或者过期,然后需要做一些处理(细节就不多说了)
设置的tomcat某个项目的session过期时间是30分钟

但是问题就出现了,问题如下:


当我调用了session.isValid()和session.expiring查看时发现,
session很短的时间内就会被判断为无效,因为我页面没有一直刷新可能也就一分钟左右没操作页面,
但是这个session时候并没有过期.

有效测试:session.isValid()返回 false  //session已经是无效了
过期测试:session.expiring 返回 false  //说明没有过期

我想问大家的是在session没有过期时期,这个判断无效(isValid())的方法运行的原理是什么?
当前session是否真的是无效了
   发表时间:2012-09-20  
引用
public boolean isValid()
  {
    if (this.expiring) { //如果已经过期返回true
      return true;
    }

    if (!(this.isValid)) { //如果没有过期 则返回false
      return false;
    }

    if ((ACTIVITY_CHECK) && (this.accessCount.get() > 0)) {
      return true;
    }

    if (this.maxInactiveInterval >= 0) { //判断当前访问时间-上次访问时间 如果超过maxInactiveInterval 过期session
      long timeNow = System.currentTimeMillis();
      int timeIdle = (int)((timeNow - this.thisAccessedTime) / 1000L);
      if (timeIdle >= this.maxInactiveInterval) {
        expire(true); //过期方法
      }
    }

    return this.isValid;
  }



引用
  public void expire(boolean notify)
  {
    if (this.expiring) {
      return;
    }
    synchronized (this)
    {
      if (this.manager == null) {
        return;
      }
      this.expiring = true; //设置expiring=true

      Context context = (Context)this.manager.getContainer();
      Object[] listeners = context.getApplicationLifecycleListeners();
      if ((notify) && (listeners != null)) {
        HttpSessionEvent event = new HttpSessionEvent(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
          {
            fireContainerEvent(context, "beforeSessionDestroyed", listener);

            listener.sessionDestroyed(event);
            fireContainerEvent(context, "afterSessionDestroyed", listener);
          }
          catch (Throwable t)
          {
            try {
              fireContainerEvent(context, "afterSessionDestroyed", listener);
            }
            catch (Exception e)
            {
            }

            this.manager.getContainer().getLogger().error(sm.getString("standardSession.sessionEvent"), t);
          }
        }
      }

      if (ACTIVITY_CHECK) {
        this.accessCount.set(0);
      }
      setValid(false); //设置已经过期

      long timeNow = System.currentTimeMillis();
      int timeAlive = (int)((timeNow - this.creationTime) / 1000L);
      synchronized (this.manager) {
        if (timeAlive > this.manager.getSessionMaxAliveTime()) {
          this.manager.setSessionMaxAliveTime(timeAlive);
        }
        int numExpired = this.manager.getExpiredSessions();
        ++numExpired;
        this.manager.setExpiredSessions(numExpired);
        int average = this.manager.getSessionAverageAliveTime();
        average = (average * (numExpired - 1) + timeAlive) / numExpired;
        this.manager.setSessionAverageAliveTime(average);
      }

      this.manager.remove(this);

      if (notify) {
        fireSessionEvent("destroySession", null);
      }

      this.expiring = false; //expiring改为false

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


即expiring表示正在过期这个行为,不表示是否过期这个状态,过期行为执行完毕后再改为false
如果session过期isValid()肯定为false。


如果你是通过类似于如下代码得到StandardSession
   private StandardSession getStandardSession(HttpSession session) {
        try {
            StandardSessionFacade sessionFacade = (StandardSessionFacade) session;
            Field f = sessionFacade.getClass().getDeclaredField("session");
            f.setAccessible(true);
            StandardSession standardSession = (StandardSession) f.get(sessionFacade);
            return standardSession;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
则我认为这个StandardSession一直是不过期的(因为你过期了会再创建一个新的session的)

如果你是在session创建的时候把它保存下来(如放到一个Map),那调用isValid()可能返回false(这个销毁速度跟MaxInactiveInterval/直接调用invalidate有关)。

不建议使用那两个东西进行session是否过期的处理;而是要根据session是否销毁做特殊处理的话 直接用HttpSessionListener多好。

这种判断可能不正确,如session销毁了 则下次请求时得到的是一个新的session;而且你现在得到的是tomcat实现,那可能在其他类型服务器可能不好使,建议还是使用标准API来做。
0 请登录后投票
   发表时间:2012-09-21   最后修改:2012-09-21
谢谢楼上的回答和提醒,我会继续去看API和源代码研究的!
以下是我自定义的session备份,调用的是tomcat提供的backgroundProcess方法
这里我就用到了 判断session过期和是否有效的方法,发现session.isValid()会很就返回session已经无效了,但此时并没有过期.

/**
	 * tomcat中定期执行的方法,用于更新memcached中的对象保存时间
	 * 延迟的时间设置 context.xml文件context节点上的backgroundProcessorDelay属性. 单位:秒
	 */
	@Override
	public void backgroundProcess() {
		try {
			this.updateExpirationInMemcached();
		} catch (Exception e) {
			e.printStackTrace();
		}
		super.backgroundProcess();
	}
/**
	 * 定时更新session,更新session在memcached中的时间
	 * @throws Exception
	 */
private void updateExpirationInMemcached() throws Exception {
		Session [] sessions = super.findSessions();
		for(Session tmpSession: sessions){
			MemcachedSession session = (MemcachedSession)tmpSession;
			if(!session.isValid()||session.isExpiring()){
				System.out.println(session.getId() + "--有效:" + session.isValid() + "--过期:" + session.isExpiring());
				System.out.println("该会话已经过期了,从memcached中删除!");
				this.getMemcacheds().deleteKeyValue(session.getId());
				continue;
			}
			if("true".equalsIgnoreCase(this.sessionSticky)){
				//异步的更新方法
				if("binary".equalsIgnoreCase(this.protocol)){
					this.getMemcacheds().updateExpiringTime(session.getId());
				}else if("text".equalsIgnoreCase(this.protocol)){
					this.getMemcacheds().setValueNoWait(session.getId(),session);
				}
			}else{
				//同步的更新方法,因为非粘连情况,必须保证session一致性
				if("binary".equalsIgnoreCase(this.protocol)){
					this.getMemcacheds().updateExpiringTime(session.getId());
				}else if("text".equalsIgnoreCase(this.protocol)){
					this.getMemcacheds().setValue(session.getId(),session);
				}
			}
		}
	}
0 请登录后投票
   发表时间:2012-09-21  
那你应该连Session的 Manager 都替换掉啊  不应该混用啊

http://hi.baidu.com/drnadmhzfnacefe/item/87cead68940ef408a1cf0fa2
0 请登录后投票
   发表时间:2012-09-21  
tomcat中的session超时时间不是可以设置的吗
0 请登录后投票
   发表时间:2012-09-22  
public boolean isValid() 
  { 
    if (this.expiring) { //如果已经过期返回true 
      return true; 
    } 
。。。。。。


有点不明白,既然已经在做session的过期处理了,那说明当前session的随时会被销毁。为什么还要返回true啊?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics