内置缓存系统 AbsCache
在构建高性能的网络应用时,缓存系统起着至关重要的作用。Tio-boot 框架内置了一种轻量级的缓存系统——AbsCache
。本文将详细介绍如何使用 AbsCache
来缓存数据,并通过 CacheFactory
实现缓存实例的注册和管理。Tio-boot 框架内部状态都使用 AbsCache 来进行存储
简介
1. 什么是 AbsCache
AbsCache
是 Tio-boot 框架中的抽象类,用于定义缓存的核心功能。它提供了基本的缓存操作,例如存储、获取、删除缓存条目,并支持配置缓存的生存时间(TTL, Time to Live)和空闲时间(TTI, Time to Idle)。AbsCache
支持各种实现,如基于 Map
的缓存。
AbsCache
核心功能
- TTL(存活时间):缓存条目从创建开始有效,超过设定时间后将自动过期。
- TTI(空闲时间):缓存条目在最后一次访问后有一定的有效期,如果在此期间未再次访问,也会过期。
使用
1. CacheFactory 和 AbsCache 的使用流程
使用 AbsCache
时,主要通过 CacheFactory
工厂类来管理缓存实例。它可以注册并返回缓存实例,允许开发者根据需要缓存数据。
核心步骤:
- 注册缓存实例:通过
CacheFactory.register()
方法,创建或获取一个AbsCache
实例。 - 缓存数据:调用缓存实例的
put()
方法,将数据存储到缓存中。 - 获取缓存数据:使用
get()
方法,从缓存中获取数据。 - 移除缓存数据:通过
remove()
方法,删除缓存中的某个键值对。
2. 使用示例
CacheFactory cacheFactory = TioBootServer.me().getServerTioConfig().getCacheFactory();
AbsCache absCache = cacheFactory.register("test001",300L,3000L);
absCache.put("key", "value");
下面是一个简单的示例代码,展示如何向 AbsCache
缓存系统添加数据
解释:
- 缓存工厂获取:通过
TioBootServer
获取CacheFactory
实例. - 添加缓存名称:通过
register
,添加缓存名称到缓存系统。 - 添加缓存数据:通过 absCache 添加数据。
3. 实现类 ConcurrentMapCache
ConcurrentMapCache
是 AbsCache
的一个具体实现,它使用 ConcurrentHashMap
来保存缓存数据,并提供 TTL 和 TTI 的过期机制。
主要功能:
- 数据存储:
put()
方法用于将数据存储到缓存,并为缓存项设定过期时间。 - 数据获取:
get()
方法用于从缓存中获取数据,并更新 TTI 时间。 - 数据删除:
remove()
方法用于删除缓存项,并调用删除监听器。
在上面的实现中,缓存系统通过 ConcurrentHashMap
保存数据,并且会根据 TTL 和 TTI 自动过期条目。
4. 使用场景
AbsCache
适用于以下场景:
- 短期缓存:需要快速访问的数据,例如用户会话信息、临时配置等。
- 限制过期时间:当你需要在一定时间内缓存数据,且希望在不使用后自动过期。
- 轻量级缓存系统:
AbsCache
的实现轻便、易于集成,非常适合内存敏感的场景。
获取所有缓存数据
IndexController 示例
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.jfinal.kit.Kv;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.annotation.RequestPath;
import com.litongjava.tio.utils.cache.AbsCache;
import com.litongjava.tio.utils.cache.CacheFactory;
import com.litongjava.tio.utils.resp.RespBodyVo;
@RequestPath("/internal")
public class InternalController {
@RequestPath()
public RespBodyVo cache() {
CacheFactory cacheFactory = TioBootServer.me().getServerTioConfig().getCacheFactory();
Map<String, ? extends AbsCache> map = cacheFactory.getMap();
Kv kv = Kv.by("cacheFactory", cacheFactory);
kv.set("map", map);
for (Map.Entry<String, ? extends AbsCache> entry : map.entrySet()) {
String cacheName = entry.getKey();
AbsCache cache = entry.getValue();
Collection<String> keysCollection = cache.keysCollection();
Map<String, Object> cacheMap = new HashMap<>();
for (String key : keysCollection) {
cacheMap.put(key, cache.get(key));
}
kv.set("cache_" + cacheName, cacheMap);
}
return RespBodyVo.ok(kv);
}
}
返回数据格式示例
下面是一个返回的 JSON 数据格式示例:
{
"data": {
"cache_TIO_HTTP_STATIC_RES_CONTENT": {},
"cacheFactory": "INSTANCE",
"cache_com.litongjava.tio.utils.lock.LockUtilsOBJ": {},
"cache_com.litongjava.tio.utils.lock.LockUtilsRW": {
"StrCache:getLowercase-606089688": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes653303108": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-1844712829": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes3151881": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase1217813246": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes3178825": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase1577755768": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1520117783": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"_tio_ips__0:0:0:0:0:0:0:1": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes78": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-579138113": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1381242263": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-227623528": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase12634714": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase12565974": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-1399754748": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-129587587": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes100245": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-1452090263": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1519667058": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase12115249": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-2040128046": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-1610277289": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase2024076932": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-1580933225": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes78355": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-1450561559": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase2255304": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-1383386683": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-640121764": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase-1099743112": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1749280625": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1519944307": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes-1368734941": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase1955373352": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getLowercase12392498": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
},
"StrCache:getBytes1520186523": {
"queueLength": 0,
"fair": false,
"readHoldCount": 0,
"readLockCount": 0,
"writeHoldCount": 0,
"writeLocked": false,
"writeLockedByCurrentThread": false
}
},
"cache_TIO_HTTP_SESSIONRATELIMITER_CACHENAME": {
"/?d87d6737327c4ee680f1213c67465403": {
"path": "/",
"lastAccessTime": "0",
"accessCount": 0
}
},
"cache_TIO_IP_BLACK_LIST__global__": {},
"cache_TIO_IP_STAT_null_300": {
"0:0:0:0:0:0:0:1": {
"durationType": "300",
"duration": "203",
"ip": "0:0:0:0:0:0:0:1",
"handledPackets": 0,
"handledPacketCosts": 0,
"receivedPackets": 1,
"handledCostsPerPacket": 0,
"packetsPerTcpReceive": 1,
"bytesPerTcpReceive": 1469,
"handledBytes": 0,
"sentPackets": 0,
"receivedTcps": 1,
"receivedBytes": 1469,
"sentBytes": 0,
"requestCount": 2,
"start": "2024-09-08 22:16:41",
"decodeErrorCount": 0,
"formatedDuration": "203毫秒"
}
},
"map": {
"com.litongjava.tio.utils.lock.LockUtilsOBJ": {
"cacheName": "com.litongjava.tio.utils.lock.LockUtilsOBJ",
"timeToIdleSeconds": "3600",
"timeToLiveSeconds": null
},
"TIO_HTTP_SESSIONRATELIMITER_CACHENAME": {
"cacheName": "TIO_HTTP_SESSIONRATELIMITER_CACHENAME",
"timeToIdleSeconds": null,
"timeToLiveSeconds": "60"
},
"tio-h-s": {
"cacheName": "tio-h-s",
"timeToIdleSeconds": "1800",
"timeToLiveSeconds": null
},
"TIO_IP_STAT_null_300": {
"cacheName": "TIO_IP_STAT_null_300",
"timeToIdleSeconds": null,
"timeToLiveSeconds": "300"
},
"TIO_HTTP_STATIC_RES_CONTENT": {
"cacheName": "TIO_HTTP_STATIC_RES_CONTENT",
"timeToIdleSeconds": null,
"timeToLiveSeconds": "600"
},
"com.litongjava.tio.utils.lock.LockUtilsRW": {
"cacheName": "com.litongjava.tio.utils.lock.LockUtilsRW",
"timeToIdleSeconds": "3600",
"timeToLiveSeconds": null
},
"TIO_IP_BLACK_LIST__global__": {
"cacheName": "TIO_IP_BLACK_LIST__global__",
"timeToIdleSeconds": null,
"timeToLiveSeconds": "10368000"
}
},
"cache_tio-h-s": {}
},
"ok": true,
"code": 1,
"msg": null
}
使用 Caffeine 作为内置存储
当配置开启 session 时,tio-boot 会将浏览器的 session 信息存储到默认的 ConcurrentMapCache
中。但是,ConcurrentMapCache
的实现并不高效,您可以选择更换为 Caffeine。
只需添加以下依赖,tio-boot 在启动时如果检测到 com.github.benmanes.caffeine.cache.LoadingCache
存在,会自动启用 CaffeineCacheFactory
:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.9.3</version>
</dependency>
开启 session 功能
server.session.enable=true
总结
Tio-boot 内置的缓存系统 AbsCache
提供了灵活且易用的缓存管理方式。通过 CacheFactory
注册并管理缓存实例,我们可以轻松实现高效的缓存机制,减少频繁数据重复计算。对于有 TTL 和 TTI 要求的场景,AbsCache
能帮助我们自动管理缓存条目的过期,提升系统性能。