序言
我计划使用 ehCache 作为会话管理实现首先检查,如果你不能使用已经提供的,并且可能更适合会话实现。如果您使用的是 Web 容器或完整的 jee 服务器,您真的应该先尝试一下
为什么
好的。你肯定不会用正确的简单方法来做这件事。这里有一些提示,为什么您可能希望将 ehCache 用于会话
- 您的服务不是 jee 服务器/Web 容器的一部分。
- 您的服务是无状态的,但有时您需要状态(框架代码)。
- 由于您和可区分客户端之间的代理,您无法区分调用,例如,您是某种服务/服务的中间件,默认不提供可区分数据,但有条件地使用 userId 或 sessionId 等参数,但不是组成性.
- 您只是没有使用 RTFM,而是想按照自己的方式进行操作。
对于 1,请检查是否可以选择像码头这样的网络容器。你当然会使用整个会话的网络访问,这不会为你弹出。
对于 2,请检查,如果 Apache Shiro 不会做你想做的事。如果没有,ehCache 可能是你的朋友。
对于 3... 欢迎来到俱乐部。
对于4...好吧,我想如果您没有阅读手册,您也不会阅读此内容。
如何
如果您想使用 ehCache 实现会话管理,请确保您的数据是可序列化的。这将减少问题并让您使用 ehCache 的敏感功能。即持久化到磁盘、缓存节点、从中恢复等等。
不要为每个会话使用一个缓存,而是为所有会话一个缓存。 sessionId 是缓存中的键,而值将转到 Map。不要忘记并发(想想 ajax 调用)。最好使用来自java.util.concurrent 的ConcurrentHashMap。但也许你是 Dr Heinz M. Kabutz 并找到一种更酷的方法来做到这一点。
我发现使用大小而不是存储元素的数量非常有帮助。您可能不知道以后会存储哪些数据/对象。不要忘记设置持久性策略。我在这里使用存储到临时文件夹。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir"/>
<cache name="vocCache"
eternal="false"
maxElementsInMemory="100MB"
maxElementsOnDisk="1GB"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU"
diskExpiryThreadIntervalSeconds="60">
<persistence strategy="localTempSwap" />
</cache>
因为我们想实现一个会话管理器,所以我们不关心timeToLiveSeconds。会话在一定的空闲时间后超时。所以我们不将元素限制为最大 ttl,而是使用timeToIdleSeconds 让元素超时。
不要打扰timeToIdleSeconds 和timeToLiveSeconds,因为您可以为元素设置特定的值以便以后添加。
驱逐
关于到期时间的注释。内存中的元素永远不会因为配置的时间而被驱逐。内存将累积,直到达到定义的内存约束。因此,如果您定义 100 个元素,如果添加了 101 个元素,memoryStoreEvictionPolicy 将被触发,并且一个元素将 - 在此配置中 - 刷新到磁盘 (ehCache 2.2)。对于磁盘存储,将有一个线程检查到期时间(diskExpiryThreadIntervalSeconds)。请参阅documentation。
因此,您必须使用 isExpired() 检查从缓存中检索到的元素,以确保它没有过期。
所以最后你会得到这样的结果:
获取
Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
Element elem = cache.get(identifier);
if (elem == null)
{
throw new SessionNotFoundException(identifier);
}
if (elem.isExpired())
{
throw new SessionExpiredException(identifier);
}
return elem.getObjectValue();
PUT
Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
// We use ttl = 0 and tti=<ttlInMinutes>, because session timeout is based on session idle timout.
element = new Element(identifier, new SessionElement(), Boolean.FALSE, (int) (timeToLive / VALUE_MS), 0);
cache.put(element);