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. angularjs地址栏传参

    1:路由定义参数 2.controller 3. 4.目标得到参数值

  2. h5 audio播放音频文件

    h5 audio播放音频文件 注:下面html中样式及不相关的内容去掉了 第一个例子 播放没有防盗链的外网音频文件是可以的 <!doctype html> <html> < ...

  3. python random使用生成随机字符串

    应用python random标准库做一个随机生成密码的程序,可以随机生成任意多个字符.(基于python2.7,如果是python3需要修改下) 案例: #-*-coding:utf-8 -*-#a ...

  4. c#实现验证某个IP地址是否能ping通

    using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Net ...

  5. 计算从哪天起应该购买预售火车票.cs

    代码直接CSC编译即可. 计算从哪天起应该购买预售火车票.cs using System; using System.Diagnostics; using System.IO; class Progr ...

  6. DDOS工具合集---CC 2.0(僵尸网络proxy,单一url,可设置cookie,refer),传奇克星(代理+单一url,可设置cookie),NetBot_Attacker网络僵尸1.0(僵尸网络,HTTP NO-Cache Get攻击模式,CC攻击,HTTP空GET请求攻击),傀儡僵尸VIP1.4版(僵尸网络,动态单一url)、上兴网络僵尸2.3、中国制造网络僵尸、安全基地网络僵尸==

    DDOS工具合集 from:https://blog.csdn.net/chinafe/article/details/74928587 CC 著名的DDOS CC工具,效果非常好!CC 2.0使用了 ...

  7. [转载]JAVA获取word表格中数据的方案

    上一个项目的开发中需要实现从word中读取表格数据的功能,在JAVA社区搜索了很多资料,终于找到了两个相对最佳的方案,因为也得到了不少网友们的帮助,所以不敢独自享用,在此做一个分享. 两个方案分别是: ...

  8. 【spark】【问题】textFile找不到文件

    2018/5/9 关于textFile读取文件的问题 问题描述: 今天第一次使用spark-shell来读取文件,我在本地建立了一个text.txt文件,然后用textFile读取生成rdd. 但是执 ...

  9. Context的作用

    context用于访问全局资源 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSta ...

  10. Helix Server 支持的文件格式

    比如,对于WMV格式的文件,访问路径可以是:mms://192.168.1.1/mov/music.wmv 对于rm格式的文件rtsp://192.168.1.1/mov/123.rm 但,比如对于格 ...