通用化本地缓存设计及其实现框架

简介

在实际业务开发过程中,有许多需要使用本地缓存的场景,如热点数据缓存、不变数据缓存等。
在这里实现一个通用化的本地缓存框架(类型),起到数据缓存、缓存定时清理等作用。

设计

失效缓存清理

程序流程图:

说明:

  • 缓存类内部实现缓存数据模型,包含缓存数据、缓存时刻。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private class CacheModel {
private VALUE object;
private Long createTime;

CacheModel(VALUE object) {
this.createTime = System.currentTimeMillis();
this.object = object;
}

VALUE getObject() {
return object;
}

Long getCreateTime() {
return createTime;
}
}
  • 遍历缓存数据对象,使用当前时间与该对象缓存时刻进行对比,若超过设置的缓存失效时间,则清理该对象。

数据按需加载

程序流程图:

说明:

  • 从缓存获取数据,首先判断缓存数据是否存在,若存在,直接返回缓存数据。
  • 缓存数据不存在,则调用缓存对象初始化时候配置的数据获取对象,获取对应数据。
1
2
3
public interface CacheAcquireOperation<KEY, VALUE> {
VALUE acquire(KEY key);
}

核心代码片段

缓存清理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private void initCacheCleanTask(String name) {
new Thread(() -> {
while (!shutdown.get()) {
sleep(10_000);
checkCleanCache();
}
}, name).start();
}

private void checkCleanCache() {
try {
lock.get(6000);
List<KEY> invalidKeys = new ArrayList<>();
for (Map.Entry<KEY, CacheModel> entry : cacheMap.entrySet()) {
KEY key = entry.getKey();
CacheModel cacheModel = entry.getValue();
if (System.currentTimeMillis() - cacheModel.getCreateTime() >= cacheTimeMillis) {
invalidKeys.add(key);
}
}
sleep(100);
invalidKeys.forEach(cacheMap::remove);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
} finally {
lock.release();
}
}

缓存获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public VALUE get(KEY key) {
if (cacheMap.containsKey(key)) {
return cacheMap.get(key).getObject();
}
if (cacheAcquireOperation != null) {
VALUE value = null;
try {
value = cacheAcquireOperation.acquire(key);
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
if (value != null) {
put(key, value);
return value;
}
}
return null;
}

用法示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void main(String[] args) throws Exception {
LocalCache<String, String> localCache = new LocalCache<String, String>("test-cache")
.cacheTimeSeconds(20)
.cacheAcquireOperation(key -> {
String value = key + "-" + System.currentTimeMillis();
System.out.println(String.format("Cache acquire operation, key: %s, value: %s", key, value));
return value;
});

for (int i = 0; i < 10; i++) {
System.out.println(localCache.get(i + "-name"));
}
TimeUnit.MILLISECONDS.sleep(10_000);
System.out.println("----------------------");
for (int i = 0; i < 10; i++) {
System.out.println(localCache.get(i + "-name"));
}
TimeUnit.MILLISECONDS.sleep(15_000);
System.out.println("----------------------");
for (int i = 0; i < 10; i++) {
System.out.println(localCache.get(i + "-name"));
}
TimeUnit.MILLISECONDS.sleep(10_000);
localCache.close();
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Cache acquire operation, key: 0-name, value: 0-name-1569833192414
0-name-1569833192414
Cache acquire operation, key: 1-name, value: 1-name-1569833192436
1-name-1569833192436
Cache acquire operation, key: 2-name, value: 2-name-1569833192437
2-name-1569833192437
Cache acquire operation, key: 3-name, value: 3-name-1569833192437
3-name-1569833192437
Cache acquire operation, key: 4-name, value: 4-name-1569833192438
4-name-1569833192438
Cache acquire operation, key: 5-name, value: 5-name-1569833192438
5-name-1569833192438
Cache acquire operation, key: 6-name, value: 6-name-1569833192438
6-name-1569833192438
Cache acquire operation, key: 7-name, value: 7-name-1569833192439
7-name-1569833192439
Cache acquire operation, key: 8-name, value: 8-name-1569833192439
8-name-1569833192439
Cache acquire operation, key: 9-name, value: 9-name-1569833192439
9-name-1569833192439
----------------------
0-name-1569833192414
1-name-1569833192436
2-name-1569833192437
3-name-1569833192437
4-name-1569833192438
5-name-1569833192438
6-name-1569833192438
7-name-1569833192439
8-name-1569833192439
9-name-1569833192439
----------------------
Cache acquire operation, key: 0-name, value: 0-name-1569833217448
0-name-1569833217448
Cache acquire operation, key: 1-name, value: 1-name-1569833217449
1-name-1569833217449
Cache acquire operation, key: 2-name, value: 2-name-1569833217449
2-name-1569833217449
Cache acquire operation, key: 3-name, value: 3-name-1569833217450
3-name-1569833217450
Cache acquire operation, key: 4-name, value: 4-name-1569833217450
4-name-1569833217450
Cache acquire operation, key: 5-name, value: 5-name-1569833217450
5-name-1569833217450
Cache acquire operation, key: 6-name, value: 6-name-1569833217450
6-name-1569833217450
Cache acquire operation, key: 7-name, value: 7-name-1569833217450
7-name-1569833217450
Cache acquire operation, key: 8-name, value: 8-name-1569833217450
8-name-1569833217450
Cache acquire operation, key: 9-name, value: 9-name-1569833217451
9-name-1569833217451

代码仓库

https://github.com/johnsonmoon/commons/blob/master/src/main/java/com/github/johnsonmoon/commons/LocalCache.java