当前最常用的三个缓存组件:ehcache、redis、memcached

其中,ehcache与应用共同运行于JVM中,属于嵌入式组件,运行效率最高,因此常被用于实现一级缓存。

在更复杂的一些系统中,由于ehcache对集群/分布式的支持相对较弱,因此还会集成redis、memcached等,实现二级缓存。

ehcache的用法非常简单,只需要引入相关的Jar包,并创建一个配置文件,就可以在开发中使用了。

1、在Maven中添加ehcache的依赖:

<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>

这个版本是发布到net.sf.ehcache的最后一个版本,也是2.x的最后一个版本。

org.ehcache上有更新的3.x版本,功能更强大,写法差异也挺大。

由于2.x的核心功能已经非常稳定,已经完全满足系统需求,也更熟悉,因此我还是选择了这个2.10.4的版本。

2、创建配置文件:ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"
updateCheck="false"
dynamicConfig="false"> <diskStore path="java.io.tmpdir/myApp"/> <!--
默认缓存 属性说明:
maxElementsInMemory:内存中可保存的最大数量
eternal:缓存中对象是否为永久的。如果是,超时设置将被忽略
timeToIdleSeconds:对象最后一次访问之后的存活时间
timeToLiveSeconds:对象创建后的存活时间
memoryStoreEvictionPolicy:内存缓存的超期清理策略
maxElementsOnDisk:硬盘中可保存的最大数量
diskExpiryThreadIntervalSeconds:磁盘超期监控线程扫描时间间隔
overflowToDisk:内存不足时,是否启用磁盘缓存
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1200"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
overflowToDisk="true">
</defaultCache> </ehcache>

把这个配置文件保存到 src/main/resource 目录下即可。

3、实现动态创建Cache

在ehcache中,有两个最基本的对象:Cache Element

其中,Cache相当于ehcache的分区,可以看成memcache中的Slab,上面配置文件中的 defaultCache 就是一个默认分区

每个Cache(分区)都类似一个Map<K, V>,可以通过Key来从Cache中返回缓存的Value

每个KV键值对,在ehcache中,被称为Element(元素)。

要将任何一个对象添加到ehcache中,都需要事先指定分区

但在配置文件中创建分区很麻烦,通常只创建一个默认分区(必须存在),然后通过一个方法来动态创建分区:

/**
* 获取Cache,当Cache不存在时自动创建
*
* @param cacheName
* @return Cache
* @author netwild@qq.com
*/
public Cache getOrAddCache(String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
synchronized (locker) {
cache = cacheManager.getCache(cacheName);
if (cache == null) {
cacheManager.addCacheIfAbsent(cacheName);
cache = cacheManager.getCache(cacheName);
}
}
}
return cache;
}

这样的话,只需要像下面的用法,就可以很方便的把对象添加到缓存中:

String cacheName = "article";
String atricleId = "A00428";
Atricle article = AtricleService.findById(atricleId);
Element element = new Element(atricleId, article);
getOrAddCache(cacheName).put(element);

动态创建的Cache并不会出现在ehcache.xml配置文件中。

值得注意的是,上面动态创建Cache的方法中,并没有为新的Cache指定任何参数,那这些参数的默认值是多少呢?

其实,当创建Cache时,如果未传入参数默认值,将自动拷贝 defaultCache 的参数设置

就是说,配置文件中 defaultCache 的超期时间等属性将直接被应用到所有动态创建的Cache。

4、ehcache关于元素超期的判断逻辑

在ehcache.xml配置文件中,有两个关于元素超期的参数:

timeToLiveSeconds:对象创建后的存活时间

timeToIdleSeconds:对象最后一次访问之后的存活时间

这两个参数我忽略了将近一年的时间,一直在配置文件中对他们都设置了同样的参数值,比如:1200(20分钟)

刚才反复实验多次,终于将这两个参数搞清楚,才明白以前的做法是错误的

首先,这两个参数都可以单独设置而省略另一个,也可以分别设置成不同的值,当然也可以设置成相同的值,就像我以前做的那样

下面分别对这几种进行说明

1)单独设置 timeToLiveSeconds:

该对象的超期时间 = 初始创建时间 + timeToLiveSeconds

因为初始创建时间是固定的,因此不管这个对象在有效期内被命中了多少次,一旦满足超期条件,该对象将被移除。

2)单独设置 timeToIdleSeconds:

该对象的超时时间 = 最近访问时间 + timeToIdleSeconds

注意与上面的区别:不再根据创建时间,而是根据最近访问时间来确定超期时间

所以这是一种动态的超期模式,即使这个参数设置为1(秒),只要保证每秒内都能get一次,那么对象也将永远不会超期。

3)分别设置 timeToLiveSeconds 及 timeToIdleSeconds :

那么将分别计算以上两种模式的超期时间,会得出两个结果,再从两个结果里找到最小的一个做为超期时间,相当于“严苛模式

但事实上,创建时间肯定会小于最近访问时间,那如果两者都设置同样的参数值,相当于 timeToIdleSeconds 永远也不会起到作用。

如果设置不同的参数值,根据具体的业务需求,可能会出现一些意料之中或者意料之外的情况。

综上所述,我的建议是,单独设置 timeToIdleSeconds 更恰当一些,对于在有效期内被频繁命中的缓存对象,可以自动“续期”。

5、最常用的操作之一:判断缓存中是否存在对象

在应用缓存的开发过程中,这是最常用的操作,目的是想要知道:目标对象是否已经被缓存过

通常下面的逻辑是:如果已被缓存过,那么直接拿出来使用;否则自力更生,完事之后再添加到缓存,下次就省事了

很多人是这样判断的:

return getOrAddCache(cacheName).get(key) != null;

但这种方式存在个问题:当缓存对象实际上存在,但值就是Null,这时就相当于忽略了缓存

所以我开始时是这样判断的:

return getOrAddCache(cacheName).isKeyInCache(key);

后来发现这种方式不会进行超期验证,就是说即使对象已经超期,只要当初被创建过,也会返回true

调整之后:

Cache cache = getOrAddCache(cacheName);
if(cache.isKeyInCache(key) && cache.getQuiet(key) != null){
return true;
}
return false;

这样就准确了!

原创:实现ehcache动态创建cache,以及超期判断的具体逻辑的更多相关文章

  1. Android实现多页左右滑动效果,支持子view动态创建和cache

    要实现多页滑动效果,主要是需要处理onTouchEvent和onInterceptTouchEvent,要处理好touch事件的子控件和父控件的传递问题. 滚动控制可以利用android的Scroll ...

  2. [SAP ABAP开发技术总结]反射,动态创建内表、结构、变量

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. JavaScript DOM动态创建(声明)Object元素

    http://www.cnblogs.com/GuominQiu/archive/2011/04/01/2002783.html 一文提及“等整个页面加载完毕后,根据用户所选的阅读机类型,再用Java ...

  4. 使用dxNavBar动态创建应用程序菜单

    一.如何动态创建dxNavBar内容: function TMain.GetAcitonByCaption(const aCategory,aCaption: string): Integer; va ...

  5. Qt Quick 组件和动态创建的对象具体的解释

    在<Qt Quick 事件处理之信号与槽>一文中介绍自己定义信号时,举了一个简单的样例.定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Co ...

  6. C#动态创建两个按钮,btn2复制btn1的Click事件,匿名委托

    现在有一个按钮btn1,要动态创建出一个btn2,需要btn2点击时调用btn1的点击. 在delphi中这种操作很简单:btn2.onClick:=btn1.onClick,因为onClick就是个 ...

  7. ehcache-----在spring和hibernate下管理ehcache和query cache

    1. 在Hibernate配置文件中设置: <!-- Hibernate SessionFactory --> <bean id="sessionFactory" ...

  8. C#动态创建Xml-LinQ方式

    C#创建Xml-LinQ方式 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  9. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

随机推荐

  1. HTML中padding和margin的区别和用法

     margin(外边距) 定义:margin是用来隔开元素与元素的间距,发生在元素本身的外部,margin用于布局分开元素使元素与元素互不相干. 提示:margin: top right bottom ...

  2. Git: 本地创建版本库用于多处同步

    问题背景 目前有一个 Android 和 一个 iOS 项目,两个项目底层使用相同的 C++ 代码.由于在开发迭代中代码时常更新,而且往往是今天 Android 部分修改一小部分,明天 iOS 部分修 ...

  3. mybatis自动生成java代码

    SSM框架没有DB+Record模式,写起来特别费劲,只能用下面的方法勉强凑合. 上图中,*.jar为下载的,src为新建的空白目录,.xml配置如下. <?xml version=" ...

  4. junit4X系列源码--总体介绍

    原文出处:http://www.cnblogs.com/caoyuanzhanlang/p/3530267.html.感谢作者的无私分享. Junit是一个可编写重复测试的简单框架,是基于Xunit架 ...

  5. [Python]Conda 介绍及常用命令

    一.介绍 Anaconda 是一个用于科学计算的 Python 发行版,支持 Linux, Mac, Windows, 包含了众多流行的科学计算.数据分析的 Python 包.其使用conda系统进行 ...

  6. jQuery的标签选择器$('p')、类选择器$('.myClass')、id选择器$('#myId')

    $()可以是$(expresion),即css选择器 $("a")构造的这个对象,是用CSS选择器构建了一个jQuery对象——它选择了所有的<a/>这个标签 $(&q ...

  7. keytool 错误:java.to.FileNotFoundException:

    老是报如题的错误: 后来才知道是因为当前的目录下没有写的权限,所以需要指定一个路径来存放android.key: keytool -genkey -alias android.key -keyalg ...

  8. PHP中利用PHPMailer配合QQ邮箱实现发邮件

    PHPMailer的介绍: 优点: 可运行在任何平台之上 支持SMTP验证 发送邮时指定多个收件人,抄送地址,暗送地址和回复地址:注:添加抄送.暗送仅win平台下smtp方式支持 支持多种邮件编码包括 ...

  9. Python类的__getitem__和__setitem__特殊方法

    class testsetandget:    kk = {};      def __getitem__(self, key):          return self.kk[key];      ...

  10. 【转】DELL R710服务器可以安装的VMWare ESX Server 4.1 全套下载带注册码

    随着R710的停产,R720随之面世,但DELL R720服务器只支持vmware esxi5.0以上,DELL客户经理给了一套系统安装后序列号无法解决,还是用4.1好了,却又发现怎么都无法安装.按网 ...