关于shiro中session过期时间;Ehcache缓存中timeToLiveSeconds和timeToIdleSeconds过期问题

背景

我在shiro session设置了过期时间不起作用、无效 博文中,提到无论是否交互,到了30分钟就会失效,一位网友提出不同意见,并给出链接
关于Ehcache缓存中timeToLiveSeconds和timeToIdleSeconds ,网友提到

补充下,shiro里有AbstractShiroFilter在收到请求后会自己更新维护session的最后一次操作时间,所以 作者的 :所以无论30分钟内,用户是否产生交互,只要到了30分钟,ehcache就会删除session!!! 是不正确的.

经过一番研究,证实我的博文中描述错误,网友所说正确。


先上结论,shiro在更新session时,也会更新ehcahce的创建时间,所以如果有交互,session会延迟过期时间。


其实长久以来,我对ehcache的过期时间也迷迷糊糊,尤其是timeToLiveSeconds、timeToIdleSeconds的关系,如果两个同时设置哪个起作用?网上众说纷纭,莫衷一是,为了获取最准确的答案,决定看源码

maven配置文件

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-ehcache</artifactId>
   <version>1.3.2</version>
</dependency>

首先要明确一个前提,eternal=false时,timeToLiveSeconds、timeToIdleSeconds才起作用。以下讨论是基于eternal=false这个大前提下,我们先看一下ehache怎么计算过期时间的

net.sf.ehcache.Element
/**
     * Returns the expiration time based on time to live. If this element also has a time to idle setting, the expiry
     * time will vary depending on whether the element is accessed.
     *
     * @return the time to expiration
     */
    public long getExpirationTime() {
        if (!isLifespanSet() || isEternal()) {
            return Long.MAX_VALUE;
        }

        long expirationTime = 0;
        long ttlExpiry = creationTime + TimeUtil.toMillis(getTimeToLive());

        long mostRecentTime = Math.max(creationTime, lastAccessTime);
        long ttiExpiry = mostRecentTime + TimeUtil.toMillis(getTimeToIdle());

        if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || lastAccessTime == 0)) {
            expirationTime = ttlExpiry;
        } else if (getTimeToLive() == 0) {
            expirationTime = ttiExpiry;
        } else {
            expirationTime = Math.min(ttlExpiry, ttiExpiry);
        }
        return expirationTime;
    }

根据源码可知

  • 如果设置了TTL,并且TTI为永久空闲或者未被访问过,那么过期时间是ttlExpiry(创建时间+TTL)
  • 如果未设置TTL(TTL=0,永久存活),那么过期时间是ttiExpiry,也就是max(创建时间,最后一次访问时间)+TTI
  • 其它情况,取 min(ttlExpiry,ttiExpiry)

以上是ehcache的过期时间计算方法,但是shiro在更新session时,会同步更新Element的createTime,所以每次访问后,创建时间会自动延迟。看源码

CachingSessionDAO.java
public void update(Session session) throws UnknownSessionException {
        doUpdate(session);
        if (session instanceof ValidatingSession) {
            if (((ValidatingSession) session).isValid()) {
                cache(session, session.getId());
            } else {
                uncache(session);
            }
        } else {
            cache(session, session.getId());
        }
    }
org.apache.shiro.cache.ehcache.EhCache
/**
     * Puts an object into the cache.
     *
     * @param key   the key.
     * @param value the value.
     */
    public V put(K key, V value) throws CacheException {
        if (log.isTraceEnabled()) {
            log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]");
        }
        try {
            V previous = get(key);
            //创建新的Element,更新createTime
            Element element = new Element(key, value);
            cache.put(element);
            return previous;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

shiro更新session时,调用了cache方法,最终调用了Ehcache的put方法,创建新的Element,取当前时间为创建时间。也就是说,shiro在更新session时,更改了ehcache中Element的创建时间,从而延长了存活时间。

现在举例说明,

1分钟时创建,TTL=4分钟,TTI =2分钟,最后一次访问时间是3分钟,那么TTLExpire=7分钟,TTIExpire=5分钟,过期时间是5分钟!!
再反过来
1分钟时创建,TTL=2分钟,TTI =4分钟,最后一次访问时间是1分钟,TTLExpire=3分钟,TTIExpire=5分钟,那么过期时间是3分钟。

总结

  • eternal=true时
    • timeToLiveSeconds、timeToIdleSeconds都不起作用,即使设置了也枉然
  • eternal=false时,
    • timeToLiveSeconds、timeToIdleSeconds起作用,TTLExpire=createTime+TTL,TTIExpire=max(creatTime,accessTime)+TTI,过期时间为min(TTLExpire,TTIExpire)
发布了336 篇原创文章 · 获赞 369 · 访问量 193万+

猜你喜欢

转载自blog.csdn.net/wangjun5159/article/details/99861552