关闭

Ehcache学习笔记

1377人阅读 评论(0) 收藏 举报

原文网址:http://rmn190.iteye.com/blog/792734

Ehcache(一): Spring + Ehcache开场白

早就想系统一点研究研究Ehcache了, 现在时机成熟了些, 于是着手这方面的研究.

    Ehcache是干啥的? 它跟别的同类产品相比有什么优势? 这些问题相信大家已有所了解,本篇先不列举,这里先搭建一个很简单地例子,以便能有一个debug方式研究ehcache的活场景.

    这个例子很简单,以AOP的方式配置了Spring+Ehcache, 并没有直接用相对新特性(ehcache:config ). 一是,新特性是基于传统的AOP发展来的,用传统的方式更能从根上来理解问题;二是,基于这个传统方式,随着对其不足的认识,一步步地去理解新特性,这样不仅仅对Ehcache有更深的认识,相信对自己的编码/设计也会有不小的提高.

    具体配置不再赘述,详见附件.

    这里先大致总结下实例中的配置思路. 总体来说, 实例是基于AOP的,即利用拦截器的特性来处理缓存. 实例中写了一个模拟从数据库里取Person的方法(PersonManagerImpl类中的getList), Spring中以ProxyFactoryBean方式给它配置了一个代理,这样当getList方法调用时, 拦截器先从cache里看看有没有想要的数据,如果有直接从cache里取,如果没有真正调用getList方法并将结果new一个Element从而缓存起来.

    这个实例中只是用到了取数据时的缓存,但若数据库里真正数据有更新时并没有考虑, 这些特性以后会逐步以实验的方式加上. 敬请关注!

 

Ehcache(二): 从EhCacheManagerFactoryBean说起

注: 跟笔者其它研究源码的博客一样, Ehcache系列也是基于一个例子来debug地跟踪, 例子详见Ehcache(一): Spring + Ehcache开场白中的附件.如果没有例子作参照,阅读过程中可能有些摸不着头绪.
--------------------

Ehcache(一): Spring + Ehcache开场白中, 创建了一个实例,从这篇起, 我们开始ehcahe源码探索之路.


    先看实例中的applicationContext配置文件说起. 配置文件中第一个bean是EhCacheManagerFactoryBean, 那么它是干啥的? 看源码,我们得知它封装了三个属性(CacheManager类型的cacheManager,boolean类型的shared和表示ehcache配置信息的configLocation).  这个类很简单,从类名和封装了的属性上也不难看出Spring用些类(afterPropertiesSet方法)来new出一个 CacheManager实例. CacheManager是Ehcache赖以运行的后防基地,这个不必多说.

    不过看afterPropertiesSet方法,它有对shared的判断. 这是干啥的? 看源码注释发现了这样的描述: whether the EHCache CacheManager should be shared (as a singleton at the VM level) or independent (typically local within the application). 也说是说通过这个来设置cache的基地是这里的Spring独用,还是跟别的(如Hibernate的Ehcache共享). 这样了就回答了我心中一个问题: 如何让Hibernate也用到Spring中启动的Ehcache?

    接下来据shared与否的设置,Spring分别通过CacheManager.create()或new CacheManager()方式来创建一个ehcache基地.

    这样一个EhCacheManagerFactoryBean创建完成, 也就代表着一个CacheManager的启用.

    下一篇中再看这个CacheManager怎么来使用?

 

Ehcache(三): Cache实例的get与set

  Ehcache(二): 从EhCacheManagerFactoryBean说起 中, 我们看到一个EhCacheManagerFactoryBean的创建并由此启用一个CacheManager实例. 结合ehcache的配置文件和CacheManager的名字,不难猜出这个实例是管理Cache的. 那么这个CacheManager实例用在了哪? 配置文件中的org.springframework.cache.ehcache.EhCacheFactoryBean实例的创建中. 那么又用这个CacheManager实例做了些什么呢? 这得看EhCacheFactoryBean类的afterPropertiesSet方法.

    方法afterPropertiesSet中有这么一段代码:

        if (this.cacheManager.cacheExists(this.cacheName)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Using existing EHCache cache region '" + this.cacheName + "'");
            }
            this.cache = this.cacheManager.getEhcache(this.cacheName);
        }
    也就是说, cacheManager会检查下配置的cacheName(即,ehcache.xml文件中名为com.rmn190.MethodCache的cache)对应的cache是否已经存在. 如果存在,就直接get出来.

    这只是get了下cacheManager中已有的cache,那么那个已有的cache是怎么创建出来的? 也就是本例中的名为com.rmn190.MethodCache的cache的cache是何时/如何创建的?

    一番顺藤模瓜后, 找到了ConfigurationHelper类中的createCache(CacheConfiguration cacheConfiguration)方法. 这里真真切切地看到了"new Cache"的调用.

    上面我们深层次地体会到Cache实例的创建并通过cacheManager给get了出来, get出来后,在Spring中就set给了例子中MethodCacheInterceptor类属性cache. 不过这里又有问题了: MethodCacheInterceptor类属性cache是一net.sf.ehcache.Cache类型的, 但Spring配置文件中set来的实例是一个 org.springframework.cache.ehcache.EhCacheFactoryBean,类型不匹配的,EhCacheFactoryBean与Cache有继承或实现关系? 看源码,没有发现. 那Spring又是怎么解决这个类型不匹配问题的?

    我们在EhCacheFactoryBean类实现的接口FactoryBean上找到了答案: getObject和getObjectType. 通过FactoryBean接口定义两个方法给出的信息,Spring就很自然而流畅地解决了类型匹配问题.

Ehcache(四): net.sf.ehcache.Cache类代表个啥?

 Ehcache(三): Cache实例的get与set 中, 我们看到一个Cache实例从CacheManager中get了出来,并又set给了MethodCacheInterceptor. 那么不禁要问: 这个get/set的Cache实例代表什么信息?

    家谱
   
本着尽可能多地吸收开源项目精华的原则, 我们还是来看Cache类的家谱. 在Eclipse中F4后,我们得到了如下所示的继承/实现关系.

如图所示, Cache类现了Ehcache接口. 再看Ehcache接口又有什么特性呢? Ehcache接口里有定义了很多方法,不过我们这里只关注现在要用到的: get,put,remove.这几个方法也折射出Cache的实质: 把数据放到缓存中, 从缓存中取出数据和从缓存中删除掉不再有意义的数据.




    上面我们从最根上看出Cache是Ehcache中存放数据的Cell,那么为了实现Ehcache接口中定义的方法(也即缓存的基本功能),这个Cache类又依赖什么或又有什么辅助属性呢? 我们看到有这样的属性:
    1, 真正存放数据的地方: diskStore(net.sf.ehcache.store.Store类型) , memoryStore(net.sf.ehcache.store.MemoryStore类型).
    2, 与命中与否相关的统计信息:  hitCount,memoryStoreHitCount,diskStoreHitCount,missCountNotFound,missCountExpired
    3, 与事件相关的监听: registeredEventListeners.
   
    何时创建/创建时用到什么信息?
       Ehcache(三): Cache实例的get与set 中我们顺藤摸瓜地看到一个Cache实例是在(或者说可以在)ConfigurationHelper类的createCache(CacheConfiguration cacheConfiguration)方法创建出来. 方法中我们看到了如下代码:

        Cache cache = new Cache(cacheConfiguration.name,
                cacheConfiguration.maxElementsInMemory,
                cacheConfiguration.memoryStoreEvictionPolicy,
                cacheConfiguration.overflowToDisk,
                getDiskStorePath(),
                cacheConfiguration.eternal,
                cacheConfiguration.timeToLiveSeconds,
                cacheConfiguration.timeToIdleSeconds,
                cacheConfiguration.diskPersistent,
                cacheConfiguration.diskExpiryThreadIntervalSeconds,
                null,
                null,
                cacheConfiguration.maxElementsOnDisk,
                cacheConfiguration.diskSpoolBufferSizeMB);

    构造方法中绝大多数地用到了cacheConfiguration实例, 写到这里相信大家也都能看出来了: 一个Cache对象对应着ehcache.xml配置文件中一个<cache>标签. 也即如下的配置信息:

        <cache name="com.rmn190.MethodCache"
            maxElementsInMemory="10"
            eternal="false"
            timeToIdleSeconds="200"
            timeToLiveSeconds="300"
            overflowToDisk="true"
            />

    也就是说,一个Cache对象对应着Ehcache项目在内存或磁盘里根据<cache>标签里信息划分出来的一个存储空间,为了使用上的方便,给这存储空间起了个名字,即<cache>标签中的name信息.

 

Ehcache(五): cache.put(element)做了些什么?

1, checkStatus(): if (!status.equals(Status.STATUS_ALIVE))
2, element.resetAccessStatistics():
        lastAccessTime = 0;
        nextToLastAccessTime = 0;
        hitCount = 0;

    怎么把一个element里的这些信息都给置成了0?
3, elementExists = isElementInMemory(key) || isElementOnDisk(key);
    判断要put进来的element是否已存在. 为什么不分是Memory和Disk呢? 

    Memory中用了Map来模拟内存, 
    
    disk判断时: diskElements.containsKey(key) || spool.containsKey(key). 
        private Map diskElements = Collections.synchronizedMap(new HashMap());
        private Map spool = new HashMap();
        
        怎么一点也看不出与disk相关的信息: 如,IO,stream等. 
4, backOffIfDiskSpoolFull
    看来这个方法里并不真正做back? 那么真正的backOff是在什么方法里做的? 

5, 真正的put
    怎么类MemoryStore里的doPut方法是空的? 

7, registeredEventListeners.notifyElementXXX方法: 
    这些监听是怎么设置的? 

 

Ehcache(1): Ehcache实例在Eclipse中的配置

跟实例对应的文章:Speed Up Your Hibernate Applications with Second-Level Caching. 这里为了研究这篇文章和Ehcache, 在Eclipse中重新配置了下,又补全了必要jar包。

下载附件内容,按如下步骤配置:

1, 在Mysql中执行others\sql目录下的create.sql和init.sql两个sql脚本,命令如: mysql>source E:\MyEclipseWorkSpace\myHiberEhCaching\others\sql\create.sql; 注: init.sql语句会执行N长时间,可先考虑执行这个。
2, 用others\lib下的jar配置classpath。 


======
另:附件中的lib下也加了些source文件, 可以debug跟踪地研究源码。

 

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1993252次
    • 积分:21104
    • 等级:
    • 排名:第369名
    • 原创:182篇
    • 转载:899篇
    • 译文:2篇
    • 评论:143条
    最新评论