oscache作为本地缓存框架,存储模型依然是通用的缓存键值对模型。oscache使用HashTable存放数据,我们看下源码:

  GeneralCacheAdministrator:

    /**
* 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}
* @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) throws NeedsRefreshException {
return getCache().getFromCache(key, refreshPeriod);
}

  Cache:

    /**
* Retrieve an object from the cache specifying its key.
*
* @param key Key of the object in the cache.
* @param refreshPeriod How long before the object needs refresh. To
* allow the object to stay in the cache indefinitely, supply a value
* of {@link CacheEntry#INDEFINITE_EXPIRY}.
* @param cronExpiry A cron expression that specifies fixed date(s)
* and/or time(s) that this cache entry should
* expire on.
*
* @return The object from cache
*
* @throws NeedsRefreshException Thrown when the object either
* doesn't exist, or exists but is stale. When this exception occurs,
* the CacheEntry corresponding to the supplied key will be locked
* and other threads requesting this entry will potentially be blocked
* until the caller repopulates the cache. If the caller choses not
* to repopulate the cache, they <em>must</em> instead call
* {@link #cancelUpdate(String)}.
*/
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; // Check if this entry has expired or has not yet been added to the cache. If
// so, we need to decide whether to block, serve stale content or throw a
// NeedsRefreshException
if (this.isStale(cacheEntry, refreshPeriod, cronExpiry)) { //Get access to the EntryUpdateState instance and increment the usage count during the potential sleep
EntryUpdateState updateState = getUpdateState(key);
try {
synchronized (updateState) {
if (updateState.isAwaitingUpdate() || updateState.isCancelled()) {
// No one else is currently updating this entry - grab ownership
updateState.startUpdate(); if (cacheEntry.isNew()) {
accessEventType = CacheMapAccessEventType.MISS;
} else {
accessEventType = CacheMapAccessEventType.STALE_HIT;
}
} else if (updateState.isUpdating()) {
// Another thread is already updating the cache. We block if this
// is a new entry, or blocking mode is enabled. Either putInCache()
// or cancelUpdate() can cause this thread to resume.
if (cacheEntry.isNew() || blocking) {
do {
try {
updateState.wait();
} catch (InterruptedException e) {
}
} while (updateState.isUpdating()); if (updateState.isCancelled()) {
// The updating thread cancelled the update, let this one have a go.
// This increments the usage count for this EntryUpdateState instance
updateState.startUpdate(); if (cacheEntry.isNew()) {
accessEventType = CacheMapAccessEventType.MISS;
} else {
accessEventType = CacheMapAccessEventType.STALE_HIT;
}
} else if (updateState.isComplete()) {
reload = true;
} else {
log.error("Invalid update state for cache entry " + key);
}
}
} else {
reload = true;
}
}
} finally {
//Make sure we release the usage count for this EntryUpdateState since we don't use it anymore. If the current thread started the update, then the counter was
//increased by one in startUpdate()
releaseUpdateState(updateState, key);
}
} // If reload is true then another thread must have successfully rebuilt the cache entry
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 we didn't end up getting a hit then we need to throw a NRE
if (accessEventType != CacheMapAccessEventType.HIT) {
throw new NeedsRefreshException(content);
} return content;
}

  继续进入getCacheEntry方法:

/**
* Get an entry from this cache or create one if it doesn't exist.
*
* @param key The key of the cache entry
* @param policy Object that implements refresh policy logic
* @param origin The origin of request (optional)
* @return CacheEntry for the specified key.
*/
protected CacheEntry getCacheEntry(String key, EntryRefreshPolicy policy, String origin) {
CacheEntry cacheEntry = null; // Verify that the key is valid
if ((key == null) || (key.length() == 0)) {
throw new IllegalArgumentException("getCacheEntry called with an empty or null key");
} cacheEntry = (CacheEntry) cacheMap.get(key); // if the cache entry does not exist, create a new one
if (cacheEntry == null) {
if (log.isDebugEnabled()) {
log.debug("No cache entry exists for key='" + key + "', creating");
} cacheEntry = new CacheEntry(key, policy);
} return cacheEntry;
}

  跟到这里,终于出现正主cacheMap:

    /**
* The actual cache map. This is where the cached objects are held.
*/
private AbstractConcurrentReadCache cacheMap = null;

  我们看下这个类AbstractConcurrentReadCache:

/**
* A version of Hashtable that supports mostly-concurrent reading, but exclusive writing.
* Because reads are not limited to periods
* without writes, a concurrent reader policy is weaker than a classic
* reader/writer policy, but is generally faster and allows more
* concurrency. This class is a good choice especially for tables that
* are mainly created by one thread during the start-up phase of a
* program, and from then on, are mainly read (with perhaps occasional
* additions or removals) in many threads. If you also need concurrency
* among writes, consider instead using ConcurrentHashMap.
* <p>
*
* Successful retrievals using get(key) and containsKey(key) usually
* run without locking. Unsuccessful ones (i.e., when the key is not
* present) do involve brief synchronization (locking). Also, the
* size and isEmpty methods are always synchronized.
*
* <p> Because retrieval operations can ordinarily overlap with
* writing operations (i.e., put, remove, and their derivatives),
* retrievals can only be guaranteed to return the results of the most
* recently <em>completed</em> operations holding upon their
* onset. Retrieval operations may or may not return results
* reflecting in-progress writing operations. However, the retrieval
* operations do always return consistent results -- either those
* holding before any single modification or after it, but never a
* nonsense result. For aggregate operations such as putAll and
* clear, concurrent reads may reflect insertion or removal of only
* some entries. In those rare contexts in which you use a hash table
* to synchronize operations across threads (for example, to prevent
* reads until after clears), you should either encase operations
* in synchronized blocks, or instead use java.util.Hashtable.
*
* <p>
*
* This class also supports optional guaranteed
* exclusive reads, simply by surrounding a call within a synchronized
* block, as in <br>
* <code>AbstractConcurrentReadCache t; ... Object v; <br>
* synchronized(t) { v = t.get(k); } </code> <br>
*
* But this is not usually necessary in practice. For
* example, it is generally inefficient to write:
*
* <pre>
* AbstractConcurrentReadCache t; ... // Inefficient version
* Object key; ...
* Object value; ...
* synchronized(t) {
* if (!t.containsKey(key))
* t.put(key, value);
* // other code if not previously present
* }
* else {
* // other code if it was previously present
* }
* }
*</pre>
* Instead, just take advantage of the fact that put returns
* null if the key was not previously present:
* <pre>
* AbstractConcurrentReadCache t; ... // Use this instead
* Object key; ...
* Object value; ...
* Object oldValue = t.put(key, value);
* if (oldValue == null) {
* // other code if not previously present
* }
* else {
* // other code if it was previously present
* }
*</pre>
* <p>
*
* Iterators and Enumerations (i.e., those returned by
* keySet().iterator(), entrySet().iterator(), values().iterator(),
* keys(), and elements()) return elements reflecting the state of the
* hash table at some point at or since the creation of the
* iterator/enumeration. They will return at most one instance of
* each element (via next()/nextElement()), but might or might not
* reflect puts and removes that have been processed since they were
* created. They do <em>not</em> throw ConcurrentModificationException.
* However, these iterators are designed to be used by only one
* thread at a time. Sharing an iterator across multiple threads may
* lead to unpredictable results if the table is being concurrently
* modified. Again, you can ensure interference-free iteration by
* enclosing the iteration in a synchronized block. <p>
*
* This class may be used as a direct replacement for any use of
* java.util.Hashtable that does not depend on readers being blocked
* during updates. Like Hashtable but unlike java.util.HashMap,
* this class does NOT allow <tt>null</tt> to be used as a key or
* value. This class is also typically faster than ConcurrentHashMap
* when there is usually only one thread updating the table, but
* possibly many retrieving values from it.
* <p>
*
* Implementation note: A slightly faster implementation of
* this class will be possible once planned Java Memory Model
* revisions are in place.
*
* <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
**/
public abstract class AbstractConcurrentReadCache extends AbstractMap implements Map, Cloneable, Serializable

  类注释说明AbstractConcurrentReadCache是一个HashTable的版本,支持读多写少的应用场景,基本上缓存都是用户读多写少的场景。接下来我们再看下oscache怎么实例化的。还是从GeneralCacheAdministrator入手:

    /**
* Create the cache administrator.
*/
public GeneralCacheAdministrator() {
this(null);
} /**
* Create the cache administrator with the specified properties
*/
public GeneralCacheAdministrator(Properties p) {
super(p);
log.info("Constructed GeneralCacheAdministrator()");
createCache();
}

  它的构造函数调用了父类AbstractCacheAdministrator的构造函数:

    /**
* Create the AbstractCacheAdministrator.
*
* @param p the configuration properties for this cache.
*/
protected AbstractCacheAdministrator(Properties p) {
loadProps(p);
initCacheParameters(); if (log.isDebugEnabled()) {
log.debug("Constructed AbstractCacheAdministrator()");
}
}

  我们看它怎么加载配置文件的:

    /**
* Load the properties file from the classpath.
*/
private void loadProps(Properties p) {
config = new Config(p);
}

  进入Config类:

    /**
* Create an OSCache configuration with the specified properties.
* Note that it is the responsibility of the caller to provide valid
* properties as no error checking is done to ensure that required
* keys are present. If you're unsure of what keys should be present,
* have a look at a sample oscache.properties file.
*
* @param p The properties to use for this configuration. If null,
* then the default properties are loaded from the <code>oscache.properties</code>
* file.
*/
public Config(Properties p) {
if (log.isDebugEnabled()) {
log.debug("OSCache: Config called");
} if (p == null) {
this.properties = loadProperties(PROPERTIES_FILENAME, "the default configuration");
} else {
this.properties = p;
}
}

  千呼万唤始出来,默认配置文件oscache.properties:

    /**
* Name of the properties file.
*/
private final static String PROPERTIES_FILENAME = "/oscache.properties";

oscache源码浅析的更多相关文章

  1. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  2. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. Struts2源码浅析-ConfigurationProvider

    ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface Configurat ...

  4. (转)【深入浅出jQuery】源码浅析2--奇技淫巧

    [深入浅出jQuery]源码浅析2--奇技淫巧 http://www.cnblogs.com/coco1s/p/5303041.html

  5. HashSet其实就那么一回事儿之源码浅析

    上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap,  本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...

  6. Android 手势识别类 ( 三 ) GestureDetector 源码浅析

    前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势.所 以,用户绘制出的一个完整的手势是需要一定的代码 ...

  7. Android开发之Theme、Style探索及源码浅析

    1 背景 前段时间群里有伙伴问到了关于Android开发中Theme与Style的问题,当然,这类东西在网上随便一搜一大把模板,所以关于怎么用的问题我想这里也就不做太多的说明了,我们这里把重点放在理解 ...

  8. 【深入浅出jQuery】源码浅析2--使用技巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  9. Android手势源码浅析-----手势绘制(GestureOverlayView)

    Android手势源码浅析-----手势绘制(GestureOverlayView)

随机推荐

  1. MongoDB快速入门(十三)- 聚合count、distinct和group

    1. count:     --在空集合中,count返回的数量为0.     > db.test.count()    0    --测试插入一个文档后count的返回值.    > d ...

  2. Apache配置的5个技巧

    AcceptMutex Apache 1.3.21和Apache 2.0中引入了AcceptMutex 指示符,该指示符给调节服务器的性能带来了一个难得的机会.该指示符配置Apache的accept( ...

  3. Spring中Bean管理的常用注解

    在Spring中,主要用于管理bean的注解分为四大类:1.用于创建对象.2.用于给对象的属性注入值.3.用于改变作用的范围.4.用于定义生命周期.这几个在开发中经常接触到,也可以说每天都会遇见.其中 ...

  4. 20 个 OpenSSH 最佳安全实践

    来源:https://linux.cn/article-9394-1.html OpenSSH 是 SSH 协议的一个实现.一般通过 scp 或 sftp 用于远程登录.备份.远程文件传输等功能.SS ...

  5. SSO 证书配置

    ssodev.crt为开发环境证书ssotest.crt为测试环境证书 将证书拷贝到目录:{JDK}\jre\lib\security 其中 {JDK} 是实际安装JDK的位置.然后cmd进入命令窗口 ...

  6. Pandas窗口函数

    为了处理数字数据,Pandas提供了几个变体,如滚动,展开和指数移动窗口统计的权重. 其中包括总和,均值,中位数,方差,协方差,相关性等. 下来学习如何在DataFrame对象上应用上提及的每种方法. ...

  7. Pandas与SQL比较

    由于许多潜在的Pandas用户对SQL有一定的了解,因此本文章旨在提供一些如何使用Pandas执行各种SQL操作的示例. import pandas as pd url = 'tips.csv' ti ...

  8. LeetCode第[62]题(Java):Unique Paths 及扩展

    题目:唯一路径(机器人走方格) 难度:Medium 题目内容: A robot is located at the top-left corner of a m x n grid (marked 'S ...

  9. 新东方雅思词汇---8.2、chron

    新东方雅思词汇---8.2.chron 一.总结 一句话总结:时间 chronic 英 ['krɒnɪk]  美 ['krɑnɪk]  adj. 慢性的:长期的:习惯性的 n. (Chronic)人名 ...

  10. 关于pytest的一些问题

    一. 测试模块内部使用fixture和测试模块调用外部公共的fixture 1. unittest框架下的测试用例模块 from selenium import webdriver import un ...