欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Ehcache 3 官方文档整理

程序员文章站 2022-03-18 13:37:13
...

介绍

什么是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.层的大小应采用金字塔式的大小,即,金字塔较高的层配置为使用的内存比下方较低的层少。

Ehcache 3 官方文档整理

可能出现的层组合

  • heap + offheap
  • heap + offheap + disk
  • heap + offheap + clustered
  • heap + disk
  • heap + clustered

多层组合put/get的顺序
-将值放入高速缓存时,它会直接进入最低层,比如heap + offheap + disk直接会存储在disk层。

  • 当获取一个值,从最高层获取,如果没有继续向下一层获取,一旦获取到,会向上层推送,同时上层存储该值。

使用

使用Ehcache3需要配置CacheManagerCache.支持编程与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}
相关标签: Java