ehcache 默认大小_Ehcache缓存从2.10升到3.5.0版本的简单用法和踩坑经验

本文介绍了Ehcache从2.x升级到3.x的变化,包括pom引用的差异、3.x的简单用法、存储策略以及升级过程中的坑点。3.x版本不再兼容2.x的Element元素,需要调整存取方式,并确保所有序列化对象正确实现序列化。此外,文章还提到了逐出策略和业务功能测试中的注意事项。
摘要由CSDN通过智能技术生成

简介:Ehcache是一个开源的,基于标准的缓存,可提升性能,卸载数据库,简化可扩展性。它是最广泛使用的基于Java的缓存。

1、echache2.xx和3.xx版本的pom引用

3.X的版本升级后不兼容2.X

2、echache3.X版本的简单用法,和2.X版本的差异

2.1 创建cache要点:(以3.X版本为例)

(1)需要一个CacheManager来管理cache。

(2)需要一个CacheConfiguration来制定创建cache的条件。

(3)可以创建CacheManager的同时创建一个cache,并确定缓存的key和value类型、堆内(heap)大小,根据需要设置堆外(offheap) 和持久化磁盘等等。

简单例子:(设置cache别名“preConfigured”,根据别名获取cache,进行存取操作)

CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()

.withCache("preConfigured", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))

.build();

cacheManager.init();//初始化缓存。或者在上面设置.build(true)来初始化。使用cacheManager时必须要初始化。

//获取cache

Cache preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);

//与2.X版本的差异点,2.X存一个Element元素(包含键值对),3.X直接存一个键值对

preConfigured.put(1L, "one");

//根据key获取

String value = preConfigured.get(1L);

//删除cache

cacheManager.removeCache("preConfigured");

//若需要释放CacheManager提供给它管理的cache实例的所有瞬时资源(内存、线程等),调用CacheManager.close()来关闭所有的cache实例

cacheManager.close();

持久化硬盘的例子:

// 初始化配置缓存管理器,设置堆内存大小、磁盘持久化路径、磁盘存储缓存大小

PersistentCacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()

.with(CacheManagerBuilder.persistence(storePath + File.separator + tempFilePath + File.separator))

//持久化硬盘路径

.withCache("preConfigured", CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, CacheObj.class,

ResourcePoolsBuilder.newResourcePoolsBuilder()

.heap(40, MemoryUnit.MB) //堆内,单位可选KB、MB、GB,也可设缓存的单位个数

.offheap(50, MemoryUnit.MB) //堆外

.disk(10, MemoryUnit.GB, true))) //硬盘,第三个boolean参数设置是否持久化

.build(true);//创建并初始化

(4)也可以创建完CacheManager之后,再创建一个新的cache实例,制定配置。

private Cache createCache(String cacheName, CacheManager cacheManager) {

//设置cache的配置

CacheConfiguration cacheConfiguration = newCacheConfigurationBuilder(Long.class, String.class, heap(10))

.withSizeOfMaxObjectGraph(1000)//可选配置,遍历一个对象图的时候的最多对象数

.withSizeOfMaxObjectSize(1000, MemoryUnit.B)//withSizeOfMaxObjectSize,单个对象的最大size .withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.HOURS)))//withExpiry过期策略,timeToLiveExpiration是cache生存时间,即创建cache后可以存在多久;timeToIdleExpiration cache闲置时间,即最近一次使用cache之后最多可以闲置多久;noExpiration 永不过期

.build();

//创建一个cache实例

Cache myCache = cacheManager.createCache(cacheName,cacheConfiguration);

return myCache;

}

2.2 cache的存储方式

Ehcache提供4种存储策略:heap、offheap、disk、clustered

存储速度依次降低,主要使用前3种做本地缓存。

(1)heap就是指java堆内存,这个会被GC,所以最好数量不要太大。太多的cache会造成堆内存使用减少,参考JVM堆内存设置。heap不需要序列化和反序列化。(坑点之一)

(2)offheap是堆外内存,不会受GC影响,但须以value形式存储cache,需要序列化和反序列化,性能比heap慢。启用offheap必须要确定是否开启了-XX:MaxDirectMemorySize=size[g|G|m|M|k|K],如果没设置则默认不开启,就无法使用offheap

(3)disk是磁盘存储,需要指定存储路径,速度也更慢。

(4)clustered是集群层缓存方式,表示一个客户端连接到存储缓存的服务器集群,也是JVM之间共享缓存的一种方式。一般不用,感兴趣的可以看官方文档了解。

可以搭配使用的存储层方案:

heap + offheap

heap + offheap + disk

heap + disk

heap + offheap + clustered

heap + clustered

2.3 Ehcache3.X和2.X版本使用差异

3.X版本不兼容2.X的用法,2.X版本的用法参考:https://www.cnblogs.com/qlqwj...

使用过程的差异点:

(1)缓存管理器CacheManager的创建和配置方式不同

(2)缓存配置CacheConfiguration的各种属性用法不同

(3)存取元素方式不同,2.X版本最大特点是使用了Element作为一个缓存元素对象,3.X版本不支持这种存取方式。

(4)其它待补充...

2.4 逐出策略

在2.x版本,我们可以选择LRU以及FIFO、LFU,CacheConfiguration配置memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)。在3.x中提供了EvictionAdvisor,通过继承此类可以实现采取哪种方式逐出。3.X版本官方不建议逐出,默认满了就不添加了,这里没做研究,可参考官方文档。

3、升级过程的坑点

3.1因为存取元素的方式不同,所以重构代码时,需要对存放的value数据类型做特殊处理。

value支持存放对象类型,由于我们使用三层存储方式heap+offheap+disk,所以value需要序列化和反序列化,自定义对象类必须实现序列化。

下面对比升级前后的存取写法:

2.X版本:核心在于Element元素

3.X版本:value存放的CacheObj对象类实现了序列化

3.2 踩坑注意:

你以为value存的对象类CacheObj实现序列化就OK了吗,一开始我也这么认为,所以不断调试了很多次但是结果都扑街,一度怀疑我的代码人生。

这里CacheObj类确实要序列化,并且里面存放的子对象也要实现序列化。下图画红圈处。

单元测试接口只是构造了简单的String数据,测试存取没问题后就一直去测业务功能了。所以提醒大家新写接口时不仅要单元测试,还要构造和实际业务参数一样的参数类型。

这里Object我们传进来的是一个Port对象类,Port类也实现了序列化,这就奇怪了不可能还有问题啊?! 后面不断debug到组件的内部源代码,put进去时抛了一个StoreAccessException,搜索了一下说是存放的类型问题或没序列化时会报这个错。。。最后调试发现java.io.NotSerializableException异常,检查Port类发现里面竟然重写了readObject和writeObject方法并且直接抛出不能序列化异常。(坑die)

3.3 业务功能测试踩坑

Map entitys = getResultMap(neUtil);//获取缓存方法

每次获取缓存并赋给entitys,这里entitys对象和getResultMap(neUtil) 应该指向同一块内存空间。

后面每次获取数据后填充entitys对象。

所以当entitys对象值修改时,缓存内容相应的也修改才对。

原来的实现逻辑是这样的。

但是升级ehcache组件后,打日志调试发现每次entitys对象填充后,getResultMap(neUtil)的值并没有一起改变。

所以我在后面加了一行,每次填充entitys对象后立刻put到缓存里。测试结果OK。

这里猜想可能是缓存和内存的存取时间差影响,打断点时也是可以取到,或者ehcache升级后不再使用Element元素,直接存取键值对导致对象地址变了?可以留言一起探讨哦。

到这里,ehcache组件升级算是告一段落。还有很多特性配置和性能方面没有介绍。感兴趣可参考官方文档。

我们秋名山再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值