最近看到红薯的J2Cache强大到不行,居然长期占据开源中国开源项目排行榜,偶就气不打一处来。
话说你是开源中国第一帅,这个咱们大家有共识,确实实力在那里,我们都认了。
话说你口才比@永和 好,这个只要永和没有意见,我们也同意。
但是,做个J2Cache居然还悬赏好多次,貌似要打造成开源中国第一开源项目,这就有点过分了。不对,不是过分,是相当过分。
所以今天,偶就狠狠的扒掉@红薯 的内裤,对J2Cache进行一下深入剖析。
前面写过一篇文章,标题是吐槽一下J2Cache,吐槽过后发现J2Cache的热度居然火速上升,貌似有成为开源中国第一开源项目的意思,偶这小心脏就有点受不了了,于是决定再写一篇文章,直接狠一点把@红薯 的内裤扒掉,对J2Cache进行一下深入剖析。
Cache接口
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
53
54
55
56
|
/**
* Implementors define a caching algorithm. All implementors
* <b>must</b> be threadsafe.
* @author liudong
*/
public
interface
Cache {
/**
* Get an item from the cache, nontransactionally
* @param key cache key
* @return the cached object or null
*/
public
Object get(Object key)
throws
CacheException;
/**
* Add an item to the cache, nontransactionally, with
* failfast semantics
* @param key cache key
* @param value cache value
*/
public
void
put(Object key, Object value)
throws
CacheException;
/**
* Add an item to the cache
* @param key cache key
* @param value cache value
*/
public
void
update(Object key, Object value)
throws
CacheException;
@SuppressWarnings
(
"rawtypes"
)
public
List keys()
throws
CacheException ;
/**
* @param key Cache key
* Remove an item from the cache
*/
public
void
evict(Object key)
throws
CacheException;
/**
* Batch remove cache objects
* @param keys the cache keys to be evicted
*/
@SuppressWarnings
(
"rawtypes"
)
public
void
evict(List keys)
throws
CacheException;
/**
* Clear the cache
*/
public
void
clear()
throws
CacheException;
/**
* Clean up
*/
public
void
destroy()
throws
CacheException;
}
|
但是实际上也有改进的余地,比如把Cache换成Cache<KeyType>,这样
1
|
public
Object get(Object key)
throws
CacheException;
|
1
|
public
<T> T get(KeyType key)
throws
CacheException;
|
1
2
3
4
5
|
public
Class XxxCache
implements
Cache<String){
public
<T> T get(String key)
throws
CacheException{
......
}
}
|
CacheObject类
它的内容如下:
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
|
/**
* 所获取的缓存对象
* @author winterlau
*/
public
class
CacheObject {
private
String region;
private
Object key;
private
Object value;
private
byte
level;
public
String getRegion() {
return
region;
}
public
void
setRegion(String region) {
this
.region = region;
}
public
Object getKey() {
return
key;
}
public
void
setKey(Object key) {
this
.key = key;
}
public
Object getValue() {
return
value;
}
public
void
setValue(Object value) {
this
.value = value;
}
public
byte
getLevel() {
return
level;
}
public
void
setLevel(
byte
level) {
this
.level = level;
}
}
|
这个类,从作者的本意来说是增加了一个描述所处理缓冲对象的所在级别及区域相关的对象,但是我感觉,这个类是完全不必要的,而且正是由于它的存在导致后续围绕它的处理都是不必要的。
那么我们来看看它是怎么被使用的:
在J2HibernateCache类中
1
2
3
4
5
6
7
|
public
Object get(Object key)
throws
CacheException {
CacheObject cobj = cache.get(region, key);
if
(log.isDebugEnabled()) {
log.debug(
"get value for j2cache which key:"
+ key +
",value:"
+ cobj.getValue());
}
return
cobj.getValue();
}
|
我们来搜索一下使用CacheObject类的地方:
目光所及,点进去看,居然没有看到什么特别的地方,因此问题依然是:这个类有存在的必要么?
CacheChannel接口
这个时候又看到一个接口,叫CacheChannel,内容如下:
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
53
54
55
56
57
58
59
|
/**
* Cache Channel
* @author winterlau
*/
public
interface
CacheChannel {
public
final
static
byte
LEVEL_1 =
1
;
public
final
static
byte
LEVEL_2 =
2
;
/**
* 获取缓存中的数据
* @param region: Cache Region name
* @param key: Cache key
* @return cache object
*/
public
CacheObject get(String region, Object key);
/**
* 写入缓存
* @param region: Cache Region name
* @param key: Cache key
* @param value: Cache value
*/
public
void
set(String region, Object key, Object value);
/**
* 删除缓存
* @param region: Cache Region name
* @param key: Cache key
*/
public
void
evict(String region, Object key) ;
/**
* 批量删除缓存
* @param region: Cache region name
* @param keys: Cache key
*/
@SuppressWarnings
({
"rawtypes"
})
public
void
batchEvict(String region, List keys) ;
/**
* Clear the cache
* @param region: Cache region name
*/
public
void
clear(String region)
throws
CacheException ;
/**
* Get cache region keys
* @param region: Cache region name
* @return key list
*/
@SuppressWarnings
(
"rawtypes"
)
public
List keys(String region)
throws
CacheException ;
/**
* 关闭到通道的连接
*/
public
void
close() ;
}
|
另外看到close方法的时候,感觉这个接口的设置可能定位有改进的余地,因为它把通道层的和缓冲相关的接口混在一个里面了,表面看看问题不大,实际上在实现时会带来一些不爽,同时可能会诱导开发人员做了不合理的实现。或许这个方法应该放在CacheProvider当中去?
CacheProvider
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
|
/**
* Support for pluggable caches.
* @author liudong
*/
public
interface
CacheProvider {
/**
* 缓存的标识名称
* @return return cache provider name
*/
public
String name();
/**
* Configure the cache
*
* @param regionName the name of the cache region
* @param autoCreate autoCreate settings
* @param listener listener for expired elements
* @return return cache instance
* @throws CacheException cache exception
*/
public
Cache buildCache(String regionName,
boolean
autoCreate, CacheExpiredListener listener)
throws
CacheException;
/**
* Callback to perform any necessary initialization of the underlying cache implementation
* during SessionFactory construction.
*
* @param props current configuration settings.
*/
public
void
start(Properties props)
throws
CacheException;
/**
* Callback to perform any necessary cleanup of the underlying cache implementation
* during SessionFactory.close().
*/
public
void
stop();
}
|
CacheTester
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/**
* 缓存测试入口
* @author Winter Lau
*/
public
class
CacheTester {
public
static
void
main(String[] args) {
System.setProperty(
"java.net.preferIPv4Stack"
,
"true"
);
//Disable IPv6 in JVM
CacheChannel cache = J2Cache.getChannel();
BufferedReader in=
new
BufferedReader(
new
InputStreamReader(System.in));
do
{
try
{
System.out.print(
"> "
);
System.out.flush();
String line=in.readLine().trim();
if
(line.equalsIgnoreCase(
"quit"
) || line.equalsIgnoreCase(
"exit"
))
break
;
String[] cmds = line.split(
" "
);
if
(
"get"
.equalsIgnoreCase(cmds[
0
])){
CacheObject obj = cache.get(cmds[
1
], cmds[
2
]);
System.out.printf(
"[%s,%s,L%d]=>%s\n"
, obj.getRegion(), obj.getKey(), obj.getLevel(), obj.getValue());
}
else
if
(
"set"
.equalsIgnoreCase(cmds[
0
])){
cache.set(cmds[
1
], cmds[
2
],cmds[
3
]);
System.out.printf(
"[%s,%s]<=%s\n"
,cmds[
|