Ehcache 3 官方文档整理
介绍
什么是Ehcache?
Ehcache 是一个开源的、基于标准的,健壮、可靠、快速、简单、轻量级的java分布式缓存,支持与其他框架的集成,是Hibernate默认的CacheProvider。同时也实现了JSR107的规范,是Jcache的一种实现。
Ehcache 目前提供四层模型,支持四种级别:
- heap
- off-heap
- disk
- clustered
分层架构
Ehcache3.7 支持堆、堆外、磁盘以及集群缓存;但是除了堆之外外的三种缓存,缓存的键值对必须支持序列化和反序列化。
我们在使用的时候,可以单独使用任意一个,比如:
- heap :堆上存储-利用Java的堆上RAM内存来存储缓存条目。该层使用与Java应用程序相同的堆内存
- off-heap: 堆外内存-大小仅受可用RAM限制。不受Java垃圾回收(GC)的约束。与堆上存储相比,它相当快,但速度较慢,因为在存储和重新访问JVM堆时必须将数据移入和移出JVM堆。
- disk:利用磁盘(文件系统)存储缓存条目。存储空间充足,但比基于RAM的存储要慢得多。对于所有使用磁盘存储的应用程序,建议使用快速专用磁盘来优化吞吐量。
- clustered:群集存储-该数据存储是远程服务器上的缓存
层组合
如果要使用多个层,则必须遵守一些约束条件:
1.必须始终有堆内存
2.disk和clusterd不能同时存在
3.层的大小应采用金字塔式的大小,即,金字塔较高的层配置为使用的内存比下方较低的层少。
可能出现的层组合
- heap + offheap
- heap + offheap + disk
- heap + offheap + clustered
- heap + disk
- heap + clustered
多层组合put/get的顺序
-将值放入高速缓存时,它会直接进入最低层,比如heap + offheap + disk直接会存储在disk层。
- 当获取一个值,从最高层获取,如果没有继续向下一层获取,一旦获取到,会向上层推送,同时上层存储该值。
使用
使用Ehcache3需要配置CacheManager
和Cache
.支持编程与XML配置的方式。
编程方式
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.offheap(1, MemoryUnit.MB)
.disk(20, MemoryUnit.MB, true)))
.build();
cacheManager.init();
Cache<Long, String> preConfigured =
cacheManager.getCache("preConfigured", Long.class, String.class);
Cache<Long, String> myCache = cacheManager.createCache("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));
myCache.put(1L, "da one!");
String value = myCache.get(1L);
cacheManager.removeCache("preConfigured");
cacheManager.close();
-
CacheManagerBuilder.newCacheManagerBuilder
返回一个CacheManagerBuilder
实例 -
CacheConfigurationBuilder.newCacheConfigurationBuilder
返回一个CacheConfigurationBuilder
实例用于创建CacheConfiguration
-
ResourcePoolsBuilder.newResourcePoolsBuilder
返回一个ResourcePoolsBuilder
实例用于缓存使用可分组,disk持久层设置为true存储到磁盘 -
在使用CacheManager,需要对其进行初始化,可以通过2种方式之一进行初始化:
CacheManager.init()
,或者在CacheManagerBuilder.build(boolean init)
-
cacheManager.close()
释放所有的临时资源
XML方式
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<cache alias="foo">
<key-type>java.lang.String</key-type>
<value-type>java.lang.String</value-type>
<resources>
<heap unit="entries">20</heap>
<offheap unit="MB">10</offheap>
</resources>
</cache>
<cache-template name="myDefaults">
<key-type>java.lang.Long</key-type>
<value-type>java.lang.String</value-type>
<heap unit="entries">200</heap>
</cache-template>
<cache alias="bar" uses-template="myDefaults">
<key-type>java.lang.Number</key-type>
</cache>
<cache alias="simpleCache" uses-template="myDefaults" />
</config>
-
<cache alias="foo">
声明cache别名为foo -
<key-type>/<value-type>
指定cache的键值类型,未设置则默认为java.lang.Object
-
<resources>
资源分组 -
<cache-template name="">
抽象出缓存模型,可复用 - 名为bar的cache使用抽象缓存,覆盖缓存key 类型
为了解析XML配置,可以使用以下XmlConfiguration类型:
URL myUrl = getClass().getResource("/my-config.xml");
Configuration xmlConfig = new XmlConfiguration(myUrl);
CacheManager myCacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
缓存过期和淘汰策略
- no expiry : 永不过期
- time-to-live :创建后一段时间过期
- time-to-idle : 访问后一段时间过期
编程
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(20)))
.build();
xml
<cache alias="withExpiry">
<expiry>
<ttl unit="seconds">20</ttl>
</expiry>
<heap>100</heap>
</cache>
自定义过期策略
实现ExpiryPolicy
接口
public interface ExpiryPolicy<K, V> {
Duration INFINITE = Duration.ofNanos(Long.MAX_VALUE);
ExpiryPolicy<Object, Object> NO_EXPIRY = new ExpiryPolicy<Object, Object>() {
@Override
public Duration getExpiryForCreation(Object key, Object value) {
return INFINITE;
}
@Override
public Duration getExpiryForAccess(Object key, Supplier<?> value) {
return null;
}
@Override
public Duration getExpiryForUpdate(Object key, Supplier<?> oldValue, Object newValue) {
return null;
}
};
Duration getExpiryForCreation(K key, V value);
Duration getExpiryForAccess(K key, Supplier<? extends V> value);
Duration getExpiryForUpdate(K key, Supplier<? extends V> oldValue, V newValue);
}
接口方法返回值
返回值类型 | 含义 |
---|---|
some Duration | 表示将在该持续时间之后过期, |
Duration.ZERO | 表示立即过期, |
Duration.INFINITE | 表示映射将永不过期, |
null Duration | 表示将保留先前的到期时间不变,这在创建时是非法的。 |
使用自定义过期策略:
编程
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(new CustomExpiry())
.build();
xml
<cache alias="withCustomExpiry">
<expiry>
<class>com.pany.ehcache.MyExpiry</class>
</expiry>
<heap>100</heap>
</cache>
序列化
除了堆上的存储外,所有存储都需要某种形式的对象序列化/反序列化才能存储和检索映射。这是因为它们不能在内部存储纯Java对象,而只能存储它们的二进制表示形式。
配置序列化
- 缓存配置级
CacheConfigurationBuilder.withKeySerializer(Class<? extends Serializer<K>> keySerializerClass)
CacheConfigurationBuilder.withKeySerializer(Serializer<K> keySerializer)
CacheConfigurationBuilder.withValueSerializer(Class<? extends Serializer<V>> valueSerializerClass)
CacheConfigurationBuilder.withValueSerializer(Serializer<V> valueSerializer)
- 缓存管理器级
CacheManagerBuilder.withSerializer(Class<C> clazz, Class<? extends Serializer<C>> serializer)
缓存配置优先于缓存管理器,即缓存配置会覆盖缓存管理器
Ehcache支持以下序列化,按顺序处理
- java.io.Serializable
- java.lang.Long
- java.lang.Integer
- java.lang.Float
- java.lang.Double
- java.lang.Character
- java.lang.String
- byte[]
自定义序列化
自定义序列化需要实现org.ehcache.spi.serialization.Serializer
接口
public interface Serializer<T> {
ByteBuffer serialize(T object) throws SerializerException;
T read(ByteBuffer binary) throws ClassNotFoundException, SerializerException;
boolean equals(T object, ByteBuffer binary) throws ClassNotFoundException, SerializerException;
}
注意
- 实现类必须提供一个带有ClassLoader参数的构造器,比如
public MySerializer(ClassLoader classLoader) {
}
- 实现类必须线程安全
- 被序列化对象的class必须被保存;被序列化对象的class与反序列化后的对象的class必须相等。(如果在构造CacheManager时没有指定classLoader,则使用ehcache的默认classLoader)
同时如果实现 java.io.Closeable 接口,当关闭缓存管理器时,将调用该序列化器的close方法。
用户管理缓存
用户管理的缓存提供了一种直接配置缓存的简单方法,而无需设置或使用CacheManager的复杂性。即缓存要求比较简单可以使用考虑用户管理缓存。UserManagedCache
主要使用:方法本地缓存,线程本地缓存或缓存的生命周期短于应用程序生命周期的任何其他地方。
示例
UserManagedCache<Long, String> userManagedCache =
UserManagedCacheBuilder.newUserManagedCacheBuilder(Long.class, String.class)
.build(false);
userManagedCache.init();
userManagedCache.put(1L, "da one!");
userManagedCache.close();
用户管理持久化缓存
如果需要缓存持久化可以使用PersistentUserManagedCache
.如果要使用磁盘持久性缓存,则需要创建持久性服务并对其进行生命周期管理:
示例
LocalPersistenceService persistenceService = new DefaultLocalPersistenceService(new DefaultPersistenceConfiguration(new File(getStoragePath(), "myUserData")));
PersistentUserManagedCache<Long, String> cache = UserManagedCacheBuilder.newUserManagedCacheBuilder(Long.class, String.class)
.with(new UserManagedPersistenceContext<>("cache-name", persistenceService))
.withResourcePools(ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10L, EntryUnit.ENTRIES)
.disk(10L, MemoryUnit.MB, true))
.build(true);
// Work with the cache
cache.put(42L, "The Answer!");
assertThat(cache.get(42L), is("The Answer!"));
cache.close();
cache.destroy();
persistenceService.stop();
缓存监听
缓存侦听器允许实现者注册将在发生缓存事件时执行的回调方法。
监听器是在缓存级别注册的,因此只接收已注册的缓存的事件。
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(new ListenerObject(), EventType.CREATED, EventType.UPDATED)
.unordered().asynchronous();
final CacheManager manager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("foo",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(10))
.add(cacheEventListenerConfiguration)
).build(true);
final Cache<String, String> cache = manager.getCache("foo", String.class, String.class);
cache.put("Hello", "World");
cache.put("Hello", "Everyone");
cache.remove("Hello");
-
CacheEventListenerConfiguration
使用构建器创建一个侦听器和要接收的事件的构建器
在使用缓存时,也可以添加和删除缓存事件侦听器。
ListenerObject listener = new ListenerObject();
cache.getRuntimeConfiguration().registerCacheEventListener(listener, EventOrdering.ORDERED,
EventFiring.ASYNCHRONOUS, EnumSet.of(EventType.CREATED, EventType.REMOVED));
cache.put(1L, "one");
cache.put(2L, "two");
cache.remove(1L);
cache.remove(2L);
cache.getRuntimeConfiguration().deregisterCacheEventListener(listener);
cache.put(1L, "one again");
cache.remove(1L);
事件触发行为
初始值 | 操作 | 新值 | 事件 |
---|---|---|---|
{} | put(K, V) | {K, V} | created {K, null, V} |
{K, V1} | put(K, V2) | {K, V2} | updated {K, V1, V2} |
{} | put(K, V) [immediately expired] | {} | none |
{K, V1} | put(K, V2) [immediately expired] | {} | none |
{} | putIfAbsent(K, V) | {K, V} | created {K, null, V} |
{} | putIfAbsent(K, V) [immediately expired] | {} | none |
{K, V1} | replace(K, V2) | {K, V2} | updated {K, V1, V2} |
{K, V1} | replace(K, V2) [immediately expired] | {} | none |
{K, V1} | replace(K, V1, V2) | {K, V2} | updated {K, V1, V2} |
{K, V1} | replace(K, V1, V2) [immediately expired] | {} | no events |
{K, V} | remove(K) | {} | removed {K, V, null} |
推荐阅读
-
使用Python3内置文档高效学习以及官方中文文档
-
AsyncTask官方文档教程整理
-
使用Python3内置文档高效学习以及官方中文文档
-
首次公开!2020年金3,朋友面完阿里、滴滴、美团、携程后,整理的一份Java文档
-
AsyncTask官方文档教程整理
-
Hyperledger Fabric 2.0 官方文档中文版 第3章 关键概念
-
PHP框架:Medoo中文文档 didphp 二零一四年3月12日整理
-
首次公开!2020年金3,朋友面完阿里、滴滴、美团、携程后,整理的一份Java文档
-
PHP框架:Medoo中文文档 didphp 二零一四年3月12日整理
-
Unity 3D 官方文档 UGUI总览 IMGUI OnGUI Editor脚本初窥1