4. Ehcache 页面缓存的配置
4.1. Ehcache 的类层次模型
主要为三层,最上层的是 CacheManager ,他是操作 Ehcache 的入口。我们可以通过 CacheManager.getInstance() 获得一个单子的 CacheManger ,或者通过 CacheManger 的构造函数创建一个新的 CacheManger 。每个 CacheManager 都管理着多个 Cache 。而每个 Cache 都以一种类 Hash 的方式,关联着多个 Element 。 Element 则是我们用于存放要缓存内容的地方。
4.2. 环境搭建
将 ehcache-2.1.0-distribution.tar.gz :以及 ehcache-web-2.0.2-distribution.tar.gz 解压得到需要将它们放置到 WEB-INF/lib 下。有一个重要的配置文件 ehcache.xml ,可以从 ehcache 组件包中拷贝一个,也可以自己建立一个。需要放到 classpath 下。常放的路径为 /WEB-INF/classes/ehcache.xml 。
4.3. Ehcache 配置文件中元素说明
ehcach.xml 配置文件主要参数的解释 , 其实文件里有详细的英文注释 //DiskStore 配置,
cache 文件的存放目录 ,主要的值有
² user.home - 用户主目录
² user.dir - 用户当前的工作目录
² java.io.tmpdir - Default temp file path 默认的 temp 文件目录
实例:
首先设置 EhCache ,建立配置文件 ehcache.XML,默认的位置在 class- path,可以放
到你的 src 目录下:
<?xml version="1.0" encoding="UTF-8"? >
<ehcache >
<diskStore path="Java.io.tmpdir"/ >
<defaultCache
maxElementsInMemory="10000" <!- 缓存最大数目 ->
eternal="false" <!- 缓存是否持久 ->
overflowToDisk="true" <!- 当系统当机时,是否保存到磁盘 ->
timeToIdleSeconds="300" <!- 当缓存闲置 n 秒后销毁 ->
timeToLiveSeconds="180" <!- 当缓存存活 n 秒后销毁->
diskPersistent="false"
diskExpiryThreadIntervalSeconds= "120"/ >
</ehcache >
了解 ehcache 的几个概念,
Ø timeToIdleSeconds ,多长时间不访问该缓存,那么 ehcache 就会清除该缓存。
Ø timeToLiveSeconds ,缓存的存活时间,从开始创建的时间算起。
Ehcache 的三种清空策略:
1. FIFO ,first in first out ,这个是大家最熟的,先进先出。
2. LFU , Less Frequently Used ,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个 hit 属性,hit 值最小的将会被清出缓存。
3. LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
首页的页面缓存:
一个网站的首页估计是被访问的次数最多的,我们可以考虑给首页做一个页面缓存。
缓存策略:我认为应该是某个固定时间之内不变的,比如说 2 分钟更新一次,以应用
结构 page-filter-action-service-dao-db 为例。
位置:页面缓存做到尽量靠近客户的地方,就是在 page 和 filter 之间 ,这样的优
点就是第一个用户请求之后,页面被缓存,第二个用户再来请求的时候,走到 filter 这
个请求就结束了,无需再走后面的 action- service-dao-db 。带来的好处是服务器压力的减低和客户段页面响应速度的加快。
首页的页面缓存的存活时间,我们定的是 2 分钟,那么也就是说我们的timeToLiveSeconds 应该设置为 120 ,同时我们的 timeToIdleSeconds 最好也设置为 2 分钟,或者小于 2 分钟。
我们来看一下下面这个配置,这个配置片段应该放到 ehcache.xml 中:SimplePageCachingFilter 是缓存的名字,maxElementsInMemory 表示内存中SimplePageCachingFilter 缓存中元素的最大数量为 10,maxElementsOnDisk 是指持久化
该缓存的元素到硬盘上的最大数量也为 10 ,eternal=false 意味着该缓存会死亡。overflowToDisk=true 意思是表示当缓存中元素的数量超过限制时,就把这些元素持久化到硬盘,如果 overflowToDisk 是 false ,那么 maxElementsOnDisk 的设置就没有什么意义了。memoryStoreEvictionPolicy=LFU 是指按照缓存的 hit 值来清除,也就是说缓存满了之后,新的对象需要缓存时,将会将缓存中 hit 值最小的对象清除出缓存,给新的对象腾出地方来了。
接着我们来看一下 SimplePageCachingFilter 的配置,
XML/HTML 代码
<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
<filter-class>
<filter>
<filter-mapping>
<filter-name>indexCacheFilterfilter-name>
<url-pattern>*index.actionurl-pattern>
<filter-mapping>
就只需要这么多步骤,我们就可以给某个页面做一个缓存的,把上面这段配置放到你的
web.xml 中,那么当你打开首页的时候,你会发现,2 分钟才会有一堆 sql 语句出现在控
制台上。当然你也可以调成 5 分钟,总之一切都在控制中。
好了,缓存整个页面看上去是非常的简单,甚至都不需要写一行代码,只需要几行配置
就行了,够简单吧,虽然看上去简单,但是事实上内部实现却不简单哦,有兴趣的话,
大家可以看看 SimplePageCachingFilter 继承体系的源代码。
上面的配置针对的情况是缓存首页的全部,如果你只想缓存首页的部分内容时,你需要
使用 SimplePageFragmentCachingFilter 这个 filter。我们看一下如下片断:
XML/HTML 代码
<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter
<filter-class>
filter>
<filter-mapping>
<filter-name>indexCacheFilter</filter-name>
<url-pattern>*/index_right.jsp</url-pattern>
<filter-mapping>
这个 jsp 需 要被 jsp:include 到其他页面,这样就做到局部页面的缓存。这一点貌似没有 oscache 的 tag 好用。事实上在 cachefilter 中还有一个特性,就是 gzip,也就是说缓存中的元素是被压缩过的,如果客户浏览器支持压缩的话,filter 会直接返回压缩过的流,这样节省了带宽,把解压的工作交给了客户浏览器,如果客户的浏览器不支持 gzip,那么 filter 会把缓存的元素拿出来解压后再返回给客户浏览器(大多数爬虫是不支持 gzip 的,所以 filter 也会解压后再返回流),这样做的优点是节省带宽,缺点就是增加了客户浏览器的负担(但是我觉得对当代的计算机而言,这个负担微乎其微)。好了,如果你的页 面正好也需要用到页面缓存,不防可以考虑一下 ehcache,因为它实在是非常简单,而且易用。
总结:ehcache 是一个非常轻量级的缓存实现,而且从 1.2 之后就支持了集群,目前的最新版本是 1.3,而且是 hibernate 默认的缓存 provider。虽然本文是介绍的是 ehcache 对页面缓存的支持,但是 ehcache 的功能远不止如此,当然要使用好缓存,对 JEE 中缓存的原理,使用范围,适用场景等等都需要有比较深刻的理解,这样才能用好缓存,用对缓存。
最后复习一下 ehcache 中缓存的 3 种清空策略:
1. FIFO ,first in first out ,这个是大家最熟的,先进先出,不多讲了
2. LFU , Less Frequently Used ,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个 hit 属性,hit 值最小的将会被清出缓存。
3. LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
4.4. 在工程中单独使用
1. 创建 CacheManager ( net.sf.ehcache.CacheManager )
1) 使用默认配置文件创建
CacheManager manager = CacheManager.create();
2) 使用指定配置文件创建
CacheManager manager = CacheManager.create("src/config/ehcache.xml");
3) 从 classpath 找寻配置文件并创建
URL url = getClass().getResource("/anothername.xml");
CacheManager manager = CacheManager.create(url);
4) 通过输入流创建
InputStream fis = new FileInputStream(new
File("src/config/ehcache.xml").getAbsolutePath());
try { manager = CacheManager.create(fis); } finally { fis.close(); }
2. 创建 Caches ( net.sf.ehcache.Cache )
1) 取得配置文件中预先定义的 sampleCache1 设置 , 生成一个 Cache
Cache cache = manager.getCache("sampleCache1");
2) 设置一个名为 test 的新 cache,test 属性为默认
CacheManager manager = CacheManager.create();
manager.addCache("test");
3) 设置一个名为 test 的新 cache, 并定义其属性
CacheManager manager = CacheManager.create();
Cache cache = new Cache("test", 1, true, false, 5, 2);
manager.addCache(cache);
4) 删除 cache
CacheManager singletonManager = CacheManager.create();
singletonManager.removeCache("sampleCache1");
3. 使用 Caches
1) 往 cache 中加入元素
Element element = new Element("key1", "value1");
cache.put(new Element(element);
2) 从 cache 中取得元素
Element element = cache.get("key1");
3) 从 cache 中删除元素
Cache cache = manager.getCache("sampleCache1");
Element element = new Element("key1", "value1");
cache.remove("key1");
4. 卸载 CacheManager , 关闭 Cache
manager.shutdown();