ExpiringMap使用详解
ExpiringMap使用详解
·
一、ExpiringMap概述
ExpiringMap项目地址:https://github.com/jhalterman/expiringmap
1、ExpiringMap简介
针对一些小体量的项目,存储的数据量也不是很大(如校验码)的情况下,使用 Redis会增加系统的复杂性和维护难度。
ExpiringMap就是一个轻量的Java缓存方式,它的功能和Redis类似。
ExpiringMap 是一个具有高性能,低开销,零依赖,由线程安全的 ConcurrentMap 实现过期 entries 等优点的 Map。
主要特点包括:过期策略、可变有效期、最大尺寸、侦听器过期、延迟输入加载、过期自省等。
ExpiringMap基本功能包括:
- 可设置 Map 中的 Entry 在一段时间后自动过期。
- 可设置 Map 最大容纳值,当到达 Maximum size 后,再次插入值会导致 Map 中的第一个值过期。
- 可添加监听事件,在监听到 Entry 过期时调度监听函数。
- 可以设置懒加载,在调用 get() 方法时创建对象。
2、ExpiringMap常用API
enum ExpirationPolicy
:枚举,确定 ExpiringMap 元素应如何过期,- ACCESSED 根据上次访问的时间使它们过期,即从上次访问后开始计时;
- CREATED 根据条目的创建时间使它们过期,即从创建之后开始计时。
- enum TimeUnit:枚举,确定时间单位,MILLISECONDS 时间单位毫秒,SECONDS 时间单位秒,MINUTES 时间单位分钟,HOURS 时间单位小时,DAYS 时间单位天
- interface EntryLoader<K, V>:按需加载,内有 V load(K key) 方法,调用时将 key 的新值加载到即将过期的映射中。
- interface ExpiringEntryLoader<K, V>:按需加载,并控制每个值的过期时间(即可变过期时间),内有 ExpiringValue load(K key) 方法,调用时将 key 的新值加载到即将过期的映射中。
- static final class Builder<K, V>:内部类,ExpiringMap 构造器。 默认为 ExpirationPolicy.CREATED,60 个 TimeUnit.SECONDS 到期和 Integer.MAX_VALUE 的 MAXSIZE。
static Builder<Object, Object> builder()
:创建一个 ExpiringMap 构造器,返回 ExpiringMap.Builder。- Builder<K, V> expiration(long duration, TimeUnit timeUnit):构造器中的方法,用于设置 Map 的过期时间,返回 ExpiringMap.Builder。- Builder<K, V> maxSize(int maxSize):设置 Map 的最大个数,超过限制仍要添加元素时将最先过期的元素过期。
- int getMaxSize():获取 Map 的最大个数。
- Builder<K1, V1> entryLoader(EntryLoader<? super K1, ? super V1> loader):构造器中的方法,可以设置 EntryLoader,EntryLoader 和 ExpiringEntryLoader,不能同时设置。
- Builder<K1, V1> expiringEntryLoader(ExpiringEntryLoader<? super K1, ? super V1> loader):构造器中的方法,可以设置 ExpiringEntryLoader,EntryLoader 和 ExpiringEntryLoader,不能同时设置。
- Builder<K, V> expirationPolicy(ExpirationPolicy expirationPolicy):构造器中的方法,用于设置 Map 的过期策略,返回 ExpiringMap.Builder。
Builder<K, V> variableExpiration()
:构造器中的方法,允许 Map 元素具有各自的到期时间,并允许更改到期时间。Builder<K1, V1> expirationListener(ExpirationListener<? super K1, ? super V1> listener)
:构造器中的方法,配置监听每个 Map 元素过期, 通知传入的 ExpirationListener 执行预定好的操作。- void addExpirationListener(ExpirationListener<K, V> listener):给 ExpiringMap 添加过期监听器。
- void removeExpirationListener(ExpirationListener<K, V> listener):移出 ExpiringMap 的过期监听。
- long getExpiration(K key):获取指定 key 对应的元素的过期时间,返回毫秒值。
- long getExpectedExpiration(K key):获取指定 key 预计到期时间,返货毫秒值。
- ExpirationPolicy getExpirationPolicy(K key):获取指定 key 对应的元素的过期策略。
- interface ExpirationListener<K, V>:过期监听接口,有一个 void expired(K key, V value) 方法,过期时自动调用。
- ExpiringMap<K1, V1> build():创建并返回一个 ExpiringMap。
二、使用示例
使用 ExpiringMap之前,需要引入 pom依赖。
<!-- expiringmap依赖 -->
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.11</version>
</dependency>
1、构建时设置过期时间与过期策略
/**
* 初始化一个ExpiringMap(配置过期时间、过期协议等)
*/
private final static ExpiringMap<String, String> expireCacheMap = ExpiringMap.builder()
// 设置最大值,添加第11个entry时,会导致第1个立马过期(即使没到过期时间)。默认 Integer.MAX_VALUE
.maxSize(10)
// 允许 Map 元素具有各自的到期时间,并允许更改到期时间。
.variableExpiration()
// 设置过期时间,如果key不设置过期时间,key永久有效。
.expiration(10, TimeUnit.SECONDS)
.asyncExpirationListener((key, value) -> {
log.info("expireCacheMap key数据被删除了 -> key={}, value={}", key, value);
})
//设置 Map 的过期策略
.expirationPolicy(ExpirationPolicy.ACCESSED)
.build();
public static void main(String[] args) throws InterruptedException {
expireCacheMap.put("token", UUID.randomUUID().toString());
// 模拟线程等待
TimeUnit.SECONDS.sleep(8);
String token = expireCacheMap.get("token");
long expiration = expireCacheMap.getExpiration("token");
long expectedExpiration = expireCacheMap.getExpectedExpiration("token");
log.info("token ===> " + token);
log.info("设置的过期时间 ===> " + expiration / 1000);
log.info("剩余过期时间 ===> " + expectedExpiration / 1000);
// 模拟线程等待
TimeUnit.SECONDS.sleep(10);
log.info("token ===> " + expireCacheMap.get("token"));
TimeUnit.SECONDS.sleep(60);
}
说明一下:
- maxSize:Map存储的最大值,类似队列,容量固定,当操作map容量超出限制时,最开始的元素就会依次过期,只保留最新的;
- expirationPolicy:过期策略,包括 ExpirationPolicy.ACCESSED 和 ExpirationPolicy.CREATED 两种;
- 1)ExpirationPolicy.ACCESSED :每进行一次访问,过期时间就会自动清零,重新计算;
- 2)ExpirationPolicy.CREATED:在过期时间内重新 put 值的话,过期时间会清理,重新计算;默认策略。
2、单个元素设置过期时间
/**
* 构建后给单个元素设置过期时间
*/
private final static ExpiringMap<String, String> expireCacheMap2 = ExpiringMap.builder()
// 设置最大值,添加第11个entry时,会导致第1个立马过期(即使没到过期时间)。默认 Integer.MAX_VALUE
.maxSize(10)
// 允许 Map 元素具有各自的到期时间,并允许更改到期时间。
.variableExpiration()
.asyncExpirationListener((key, value) -> {
log.info("expireCacheMap2 key数据被删除了 -> key={}, value={}", key, value);
})
//设置 Map 的过期策略
.expirationPolicy(ExpirationPolicy.ACCESSED)
.build();
public static void main(String[] args) throws InterruptedException {
expireCacheMap2.put("token", UUID.randomUUID().toString(), ExpirationPolicy.ACCESSED, 30, TimeUnit.SECONDS);
expireCacheMap2.put("token2", UUID.randomUUID().toString(), ExpirationPolicy.CREATED, 30, TimeUnit.SECONDS);
// 模拟线程等待
TimeUnit.SECONDS.sleep(10);
log.info("token ===> " + expireCacheMap2.get("token"));
log.info("设置的过期时间 ===> " + expireCacheMap2.getExpiration("token") / 1000);
log.info("剩余过期时间 ===> " + expireCacheMap2.getExpectedExpiration("token") / 1000);
log.info("token2 ===> " + expireCacheMap2.get("token2"));
log.info("设置的过期时间 ===> " + expireCacheMap2.getExpiration("token2") / 1000);
log.info("剩余过期时间 ===> " + expireCacheMap2.getExpectedExpiration("token2") / 1000);
// 模拟线程等待
TimeUnit.SECONDS.sleep(20);
log.info("token ===> " + expireCacheMap2.get("token"));
log.info("token2 ===> " + expireCacheMap2.get("token2"));
TimeUnit.SECONDS.sleep(60);
}
说明一下:
- variableExpiration:允许 Map 元素具有各自的到期时间,并允许更改到期时间。也就是说可以设置单个元素的过期时间。
3、设置懒加载
@Data
public class StudentDTO implements Serializable {
private static final long serialVersionUID = 3220190006057051497L;
private String name;
private Integer age;
}
/**
* 构建后给元素设置懒加载。适合value为引用对象
*/
private final static ExpiringMap<String, StudentDTO> expireCacheMap3 = ExpiringMap.builder()
.expiration(10, TimeUnit.SECONDS)
//设置懒加载
.entryLoader(key -> new StudentDTO())
.expirationPolicy(ExpirationPolicy.ACCESSED)
.build();
private final static ExpirationListener<String, StudentDTO> expirationListener = (key, value) -> log.info("expireCacheMap3 key数据被删除了 -> key={}, value={}", key, value);
public static void main(String[] args) throws InterruptedException {
// 构建时设置过期监听,或者添加过期监听。
expireCacheMap3.addExpirationListener(expirationListener);
// 使用懒加载时,可以不用去 put 对象,在调用 get 方法时会自动创建对象
StudentDTO studentDTO1 = expireCacheMap3.get("studentDTO1");
studentDTO1.setName("赵云");
studentDTO1.setAge(17);
log.info("studentDTO1 ===> " + expireCacheMap3.get("studentDTO1"));
TimeUnit.SECONDS.sleep(3);
log.info("token ===> " + expireCacheMap3.get("studentDTO1"));
log.info("设置的过期时间 ===> " + expireCacheMap3.getExpiration("studentDTO1") / 1000);
log.info("剩余过期时间 ===> " + expireCacheMap3.getExpectedExpiration("studentDTO1") / 1000);
// 使用懒加载时,可以不用去 put 对象,在调用 get 方法时会自动创建对象
StudentDTO studentDTO2 = expireCacheMap3.get("studentDTO2");
studentDTO2.setName("赵子龙");
studentDTO2.setAge(18);
log.info("studentDTO2 ===> " + expireCacheMap3.get("studentDTO2"));
TimeUnit.SECONDS.sleep(3);
log.info("token ===> " + expireCacheMap3.get("studentDTO2"));
log.info("设置的过期时间 ===> " + expireCacheMap3.getExpiration("studentDTO2") / 1000);
log.info("剩余过期时间 ===> " + expireCacheMap3.getExpectedExpiration("studentDTO2") / 1000);
// 模拟线程等待
TimeUnit.SECONDS.sleep(20);
log.info("studentDTO1 ===> " + expireCacheMap2.get("studentDTO1"));
log.info("studentDTO2 ===> " + expireCacheMap2.get("studentDTO2"));
TimeUnit.SECONDS.sleep(60);
}
– 求知若饥,虚心若愚。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献33条内容
所有评论(0)