/** *//**
* Get an object from the cache
*
* @param key
* The key entered by the user.
* @param refreshPeriod
* How long the object can stay in cache in seconds. To allow the
* entry to stay in the cache indefinitely, supply a value of
* {@link CacheEntry#INDEFINITE_EXPIRY}
* @param cronExpression
* A cron expression that the age of the cache entry will be
* compared to. If the entry is older than the most recent match
* for the cron expression, the entry will be considered stale.
* @return The object from cache
* @throws NeedsRefreshException
* when no cache entry could be found with the supplied key, or
* when an entry was found but is considered out of date. If the
* cache entry is a new entry that is currently being
* constructed this method will block until the new entry
* becomes available. Similarly, it will block if a stale entry
* is currently being rebuilt by another thread and cache
* blocking is enabled (<code>cache.blocking=true</code>). */ public Object getFromCache(String key, int refreshPeriod, String cronExpression) throws NeedsRefreshException { return getCache().getFromCache(key, refreshPeriod, cronExpression);
}
还是来到了Cache的#getFromCache():
public Object getFromCache(String key, int refreshPeriod, String cronExpiry) throws NeedsRefreshException { // 先尝试在缓存中查找 CacheEntry cacheEntry =this.getCacheEntry(key, null, null); // 实际缓存的对象 Object content = cacheEntry.getContent(); // 缓存访问事件类型,默认是"缓存命中" CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT; boolean reload =false; // 判断缓存是否过期 if (this.isStale(cacheEntry, refreshPeriod, cronExpiry)) { // 得到缓存更新状态 EntryUpdateState updateState = getUpdateState(key); try{ synchronized (updateState) { if (updateState.isAwaitingUpdate() || updateState.isCancelled()) { // 如果是等待更新或者取消更新,那么将更新状态设置成UPDATE_IN_PROGRESS updateState.startUpdate(); if (cacheEntry.isNew()) {// 如果缓存中没有,那么设成"没命中" accessEventType = CacheMapAccessEventType.MISS;
}else{// 设成"命中过期数据",这个后边要抛异常的 accessEventType = CacheMapAccessEventType.STALE_HIT;
}
}elseif (updateState.isUpdating()) { // 如果其他线程正在更新缓存中,那么wait,等到更新完成后notify if (cacheEntry.isNew() || blocking) { do{ try{
updateState.wait();
}catch (InterruptedException e) {
}
}while (updateState.isUpdating()); if (updateState.isCancelled()) { // 如果更新的线程取消了更新,那么缓存仍然是过期的,执行和第一个分支相同的操作 updateState.startUpdate(); if (cacheEntry.isNew()) {
accessEventType = CacheMapAccessEventType.MISS;
}else{
accessEventType = CacheMapAccessEventType.STALE_HIT;
}
}elseif (updateState.isComplete()) {
reload =true;
}else{
log.error("Invalid update state for cache entry "+ key);
}
}
}else{
reload =true;
}
}
}finally{ // 线程引用数减少1 releaseUpdateState(updateState, key);
}
} if (reload) { // 可以重新载入缓存中的数据了 cacheEntry = (CacheEntry) cacheMap.get(key); if (cacheEntry !=null) {
content = cacheEntry.getContent();
}else{
log.error("Could not reload cache entry after waiting for it to be rebuilt");
}
} // 发送缓存事件 dispatchCacheMapAccessEvent(accessEventType, cacheEntry, null); // 如果数据过期,抛出需要刷新数据的异常 if (accessEventType != CacheMapAccessEventType.HIT) { thrownew NeedsRefreshException(content);
} return content;
}
整个流程还是很好理解的,这里看一些细节,首先是#isStale()方法:
protectedboolean isStale(CacheEntry cacheEntry, int refreshPeriod, String cronExpiry) { // 判断是否需要刷新 boolean result = cacheEntry.needsRefresh(refreshPeriod) || isFlushed(cacheEntry); if ((!result) && (cronExpiry !=null) && (cronExpiry.length() >0)) { try{ // 利用计划任务的方式处理过期 FastCronParser parser =new FastCronParser(cronExpiry);
result = result || parser.hasMoreRecentMatch(cacheEntry.getLastUpdate());
}catch (ParseException e) {
log.warn(e);
}
} return result;
}
其次是获取更新状态的方法:
protected EntryUpdateState getUpdateState(String key) {
EntryUpdateState updateState; synchronized (updateStates) { // Try to find the matching state object in the updating entry map. updateState = (EntryUpdateState) updateStates.get(key); if (updateState ==null) { // It's not there so add it. updateState =new EntryUpdateState();
updateStates.put(key, updateState);
}else{ // Otherwise indicate that we start using it to prevent its // removal until all threads are done with it. updateState.incrementUsageCounter();
}
} return updateState;
}
publicint startUpdate() { if ((state != NOT_YET_UPDATING) && (state != UPDATE_CANCELLED)) { thrownew IllegalStateException("Cannot begin cache update - current state ("+ state +") is not NOT_YET_UPDATING or UPDATE_CANCELLED");
}
state = UPDATE_IN_PROGRESS; return incrementUsageCounter();
}