其实之前我完全没有接触过oscache,今天突发奇想,准备看看缓存是怎么实现的,google了一下,决定看看oscache的源码,简单的写了个TestCase:
@Test
public
void
testPojoCache()
throws
Exception
{
TestPojo pojo
=
new
TestPojo(
"
0001
"
);
pojo.setField1(
100
);
pojo.setField2(
"
100
"
);
Properties prop
=
new
Properties();
InputStream is
=
this
.getClass().getResourceAsStream(
"
oscache.properties
"
);
prop.load(is);
is.close();
GeneralCacheAdministrator cacheAdmin
=
new
GeneralCacheAdministrator(prop);
cacheAdmin.putInCache(pojo.getId(), pojo);
TestPojo cachedObj
=
(TestPojo) cacheAdmin.getFromCache(
"
0001
"
);
assertEquals(
100
, cachedObj.getField1());
assertEquals(
"
100
"
, cachedObj.getField2());
}
所以我对这个产品的熟悉程度基本为0,各位大虾看了后发现误人子弟请用砖轻拍。
简单了看了下oscache的介绍,发现它支持三种缓存方式:JSP Caching、Request
Caching、General-Purpose Cache,今天的文章就是针对最后一种General-Purpose
Cache的,在oscache中对应的入口是GeneralCacheAdministrator,就从这里开始吧:

public
GeneralCacheAdministrator(Properties p)
{
super
(p);
log.info(
"
Constructed GeneralCacheAdministrator()
"
);
createCache();
}

//
这个是super(p)调用的构造函数

protected
AbstractCacheAdministrator(Properties p)
{
loadProps(p);
initCacheParameters();

if
(log.isDebugEnabled())
{
log.debug(
"
Constructed AbstractCacheAdministrator()
"
);
}
}

//
初始化参数

private
void
initCacheParameters()
{
algorithmClass
=
getProperty(CACHE_ALGORITHM_KEY);
blocking
=
"
true
"
.equalsIgnoreCase(getProperty(CACHE_BLOCKING_KEY));
String cacheMemoryStr
=
getProperty(CACHE_MEMORY_KEY);

if
((cacheMemoryStr
!=
null
)
&&
cacheMemoryStr.equalsIgnoreCase(
"
false
"
))
{
memoryCaching
=
false
;
}

unlimitedDiskCache
=
Boolean.valueOf(config.getProperty(CACHE_DISK_UNLIMITED_KEY)).booleanValue();
overflowPersistence
=
Boolean.valueOf(config.getProperty(CACHE_PERSISTENCE_OVERFLOW_KEY))
.booleanValue();
String cacheSize
=
getProperty(CACHE_CAPACITY_KEY);

try
{
if
((cacheSize
!=
null
)
&&
(cacheSize.length()
>
0
))
{
cacheCapacity
=
Integer.parseInt(cacheSize);
}

}
catch
(NumberFormatException e)
{
log.error(
"
The value supplied for the cache capacity, '
"
+
cacheSize
+
"
', is not a valid number. The cache capacity setting is being ignored.
"
);
}
}

//
创建缓存实例

private
void
createCache()
{
log.info(
"
Creating new cache
"
);
//
这里构建缓存时用到的参数都是在父类里的#initCacheParameters()中初始化的
applicationCache
=
new
Cache(isMemoryCaching(), isUnlimitedDiskCache(), isOverflowPersistence(),
isBlocking(), algorithmClass, cacheCapacity);
configureStandardListeners(applicationCache);
}

//
Cache的构造函数
public
Cache(
boolean
useMemoryCaching,
boolean
unlimitedDiskCache,
boolean
overflowPersistence,
boolean
blocking, String algorithmClass,
int
capacity)
{
//
这里说明还是支持自定义的缓存策略的

if
(((algorithmClass
!=
null
)
&&
(algorithmClass.length()
>
0
))
&&
(capacity
>
0
))
{
try
{
cacheMap
=
(AbstractConcurrentReadCache) Class.forName(algorithmClass).newInstance();
cacheMap.setMaxEntries(capacity);
}
catch
(Exception e)
{
log.error(
"
Invalid class name for cache algorithm class.
"
+
e.toString());
}
}


if
(cacheMap
==
null
)
{
//
选择一个默认的策略

if
(capacity
>
0
)
{
//
如果有缓存数目的限制,使用LRU
cacheMap
=
new
LRUCache(capacity);
}
else
{
//
否则使用Unlimited
cacheMap
=
new
UnlimitedCache();
}
}

cacheMap.setUnlimitedDiskCache(unlimitedDiskCache);
cacheMap.setOverflowPersistence(overflowPersistence);
cacheMap.setMemoryCaching(useMemoryCaching);
this
.blocking
=
blocking;
}

//
配置事件的listener

protected
Cache configureStandardListeners(Cache cache)
{
if
(config.getProperty(PERSISTENCE_CLASS_KEY)
!=
null
)
{
cache
=
setPersistenceListener(cache);
}


if
(config.getProperty(CACHE_ENTRY_EVENT_LISTENERS_KEY)
!=
null
)
{
//
Grab all the specified listeners and add them to the cache's
//
listener list. Note that listeners that implement more than
//
one of the event interfaces will be added multiple times.
CacheEventListener[] listeners
=
getCacheEventListeners();

for
(
int
i
=
0
; i
<
listeners.length; i
++
)
{
//
Pass through the configuration to those listeners that
//
require it

if
(listeners[i]
instanceof
LifecycleAware)
{
try
{
((LifecycleAware) listeners[i]).initialize(cache, config);
}
catch
(InitializationException e)
{
log.error(
"
Could not initialize listener '
"
+
listeners[i].getClass().getName()
+
"
'. Listener ignored.
"
, e);
continue
;
}
}


if
(listeners[i]
instanceof
CacheEntryEventListener)
{
cache.addCacheEventListener(listeners[i]);
}
else
if
(listeners[i]
instanceof
CacheMapAccessEventListener)
{
cache.addCacheEventListener(listeners[i]);
}
}
}

return
cache;
}
这里对缓存#initCacheParameters()和#configureStandardListeners()里的参数大致了解下,代码里有注释良好的JavaDoc,很容易看懂。
1. cache.algorithm 缓存的策略,具体就是用哪种Map来实现缓存,默认有FIFO,LRU,Unlimited三种,也支持自定义的缓存类型的;
2. cache.blocking 是否等待新数据放入缓存,这个感觉应该是在并发读取数据的时候如果数据在其他线程正处于写入的状态这个线程会wait()直到写入线程完成写入后notifyAll();
3. cache.memory 这个是是否使用内存缓存,这个多数情况下都应该是内存的吧;
4. cache.unlimited.disk 看介绍写的是当对象需要持久化缓存(应该是串行化吧)时,是否使用无限的磁盘空间;
5. cache.persistence.overflow.only 这个说明持久化缓存是不是仅在溢出的方式下开启,字面理解应该是否仅在是memory缓存不足的情况开启持久化缓存;
6. cache.capacity 保存的对象的数目。
7. cache.persistence.class 用于持久化的类名
8. cache.event.listeners 缓存事件监听器,多个listener使用逗号分隔开
初始化大致就这么多,还是看看GeneralCacheAdministrator#putInCache()方法吧,这 里#putInCache()有4个,我挑了一个参数最多的:putInCache(String key, Object content, String[] groups, EntryRefreshPolicy policy)

/** */
/**
* Puts an object in a cache
*
*
@param
key The unique key for this cached object
*
@param
content The object to store
*
@param
groups The groups that this object belongs to
*
@param
policy The refresh policy to use
*/

public
void
putInCache(String key, Object content, String[] groups, EntryRefreshPolicy policy)
{
//
直接调用的Cache类的#putInCache
getCache().putInCache(key, content, groups, policy,
null
);
}

//
Cache的#putInCache()方法
public
void
putInCache(String key, Object content, String[] groups, EntryRefreshPolicy policy,
String origin)
{
//
首先查找这个key在缓存中是否已经存在,没有就创建一个
CacheEntry cacheEntry
=
this
.getCacheEntry(key, policy, origin);
//
判断是否是新创建的缓存
boolean
isNewEntry
=
cacheEntry.isNew();
//
[CACHE-118] If we have an existing entry, create a new CacheEntry so
//
we can still access the old one later
//
这里如果不是新的缓存也会新建一个CacheEntry,因为老的缓存值在后边也能访问到

if
(
!
isNewEntry)
{
cacheEntry
=
new
CacheEntry(key, policy);
}

cacheEntry.setContent(content);
cacheEntry.setGroups(groups);
//
放入缓存
cacheMap.put(key, cacheEntry);
//
Signal to any threads waiting on this update that it's now ready for them in the cache!
//
这里会通知其他在等待值的线程结束wait
completeUpdate(key);
//
针对缓存事件的listener发送事件

if
(listenerList.getListenerCount()
>
0
)
{
CacheEntryEvent event
=
new
CacheEntryEvent(
this
, cacheEntry, origin);

if
(isNewEntry)
{
dispatchCacheEntryEvent(CacheEntryEventType.ENTRY_ADDED, event);
}
else
{
dispatchCacheEntryEvent(CacheEntryEventType.ENTRY_UPDATED, event);
}
}
}
先简单的看看CacheEntry的构造函数吧,这个最基本:

public
CacheEntry(String key, EntryRefreshPolicy policy, String[] groups)
{
//
CacheEntry中保存了key,所属的分组(用一个HashSet保存分组的名字,有点像Tag)
//
还有刷新策略和创建的时间
this
.key
=
key;

if
(groups
!=
null
)
{
this
.groups
=
new
HashSet(groups.length);

for
(
int
i
=
0
; i
<
groups.length; i
++
)
{
this
.groups.add(groups[i]);
}
}

this
.policy
=
policy;
this
.created
=
System.currentTimeMillis();
}
另外还有#completeUpdate()方法:

protected
void
completeUpdate(String key)
{
//
Entry的更
本文介绍了oscache的General-Purpose Cache实现原理,包括初始化参数、缓存策略配置及核心方法解析,如putInCache方法的工作流程。
306

被折叠的 条评论
为什么被折叠?



