当前最常用的三个缓存组件: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. 绕过js验证

    我在火狐和谷歌下想删除对应js,由于是外部js引入的,没删掉.只好借用了工具. 这个工具也并不是多么的高大上,也许大家都用过,httprequester 步骤:打开火狐附加组件管理器——扩展——输入h ...

  2. Servlet--取得初始化配置信息

    关于这块内容,主要就是玩一个接口:ServletConfig.先翻下API,了解一下. 定义: public interface ServletConfig 这个接口定义了一个对象,通过这个对象,Se ...

  3. 在Tomcat中配置连接池和数据源

    1.DataSource接口介绍 (1)DataSource 概述 JDBC1.0原来是用DriverManager类来产生一个对数据源的连接.JDBC2.0用一种替代的方法,使用DataSource ...

  4. Ceph,TFS,FastDFS,MogileFS,MooseFS,GlusterFS 对比

    系统整体对比 对比说明 /文件系统 TFS FastDFS MogileFS MooseFS GlusterFS Ceph 开发语言 C++ C Perl C C C++ 开源协议 GPL V2 GP ...

  5. PHP实现QQ登录的开发教程

    第三方登录,就是使用大家比较熟悉的比如QQ.微信.微博等第三方软件登录自己的网站,这可以免去注册账号.快速留住用户的目的,免去了相对复杂的注册流程.下边就给大家讲一下怎么使用PHP开发QQ登录的功能. ...

  6. Bilibili/DanmakuFlameMaster: Android开源弹幕引擎·烈焰弹幕使 ~ JNI source:Bilibili/NativeBitmapFactory

    https://github.com/Bilibili/DanmakuFlameMaster

  7. 溢出问题:overflow后最后一排文字显示不全

    溢出字体会显示在padding区域(http://www.divcss5.com/css-hack/c680.shtml) section#xinwen li a h3{ border-bottom: ...

  8. centos下在php.ini设置时区

    错误: PHP Warning: Unknown: It is not safe to rely on the system's timezone settings. You are *require ...

  9. C为变量提供了5中存储模型(类)

  10. c#实现Word转换PNG图片

    由于项目需要,经过一些大神的指导以及github,stackOverflow找资料,写了个这么个程序. 主要是因为word文档有特殊字体,特殊字体处理就要用到EnhMetaFileBits,即获取一页 ...