一,引言
Ehcache 3 是 Ehcache 缓存解决方案的第三个主要版本,是一个开源的 Java 缓存库,提供了灵活、高效的缓存机制。它是 Java 生态系统中广泛使用的缓存库之一,用于加速应用程序性能和降低数据访问延迟。Ehcache 3 具有许多功能和改进,使其适用于现代应用程序的需求。
1.1 主要组件
- CacheManager:
- 描述: CacheManager 是 Ehcache 的核心组件之一,负责管理一个或多个缓存。它创建和配置缓存,并且可以通过配置文件或编程方式进行设置。
- 功能: 管理缓存的生命周期、配置缓存、管理缓存的存储策略。
- Cache:
- 描述: Cache 是 Ehcache 的核心数据结构,用于存储缓存条目。每个缓存由 CacheManager 管理,并根据配置处理数据的存储和过期策略。
- 功能: 存储数据、应用缓存策略(如过期、驱逐)、支持同步和异步操作。
- CacheConfiguration:
- 描述: CacheConfiguration 用于定义缓存的配置,如容量限制、过期策略、存储方式等。
- 功能: 配置缓存的属性,包括存储层级、过期策略、驱逐策略等。
- CacheLoader:
- 描述: CacheLoader 用于从数据源加载数据到缓存中。它是缓存的一个重要组成部分,用于数据填充和初始加载。
- 功能: 实现数据的加载逻辑,用于缓存的初始化和数据填充。
- CacheWriter:
- 描述: CacheWriter 用于将缓存的数据写入外部数据源。它允许缓存与外部存储进行交互。
- 功能: 实现缓存数据的写入逻辑,确保数据一致性和持久化。
- CacheEventListener:
- 描述: CacheEventListener 用于监听缓存的事件(如添加、更新、删除)。
- 功能: 实现事件处理逻辑,监控缓存状态变化,进行相应的处理。
1.1 功能特性
- 多级存储支持:
- 内存存储: 提供最快的数据访问速度,存在 Java 堆内存中。
- 堆外存储: 在内存外进行存储,提供额外的容量,避免 GC 暂停。
- 磁盘存储: 用于数据的持久化,提供额外的溢出空间。
- 缓存策略:
- 过期策略: 支持基于时间的过期策略,如 TTL(生存时间)和 TTI(空闲时间)。
- 驱逐策略: 提供多种驱逐策略,如 LRU(最近最少使用)、LFU(最少使用)和 FIFO(先进先出)。
- 持久化和溢出:
- 持久化: 数据可以持久化到磁盘以防丢失,支持持久化策略如
localTempSwap
。 - 溢出: 数据可以溢出到堆外存储或磁盘存储,以扩展缓存容量。
- 持久化: 数据可以持久化到磁盘以防丢失,支持持久化策略如
- 动态配置:
- 动态修改: 支持在运行时动态修改缓存的配置,如过期时间、最大条目数等。
- 集成支持:
- JCache (JSR-107) 集成: 支持 JCache 标准,允许与其他遵循 JCache 标准的缓存库进行互操作。
- Spring 集成: 与 Spring 框架无缝集成,支持 Spring 配置和管理缓存。
- 高效性能:
- 线程安全: 内存存储是线程安全的,支持多线程并发操作。
- 高效存储: 提供优化的数据存储和检索机制,减少延迟和提高性能。
- 监控和管理:
- JMX 支持: 支持通过 JMX 进行缓存监控和管理。
- 事件监听: 提供事件监听机制,允许开发人员对缓存操作进行定制处理。
二,Ehcache3快速入门
-
引入依赖
<!-- Ehcache 3.x 核心库 --> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> <version>3.10.8</version> </dependency>
-
编写配置文件
Ehcache支持API方式编辑配置文件也支持XML方式编辑配置文件,建议采用XML配置
-
API方式配置
@Configuration public class EhcacheConfig { //持久化CacheManager,要存储本地必须用这个 private PersistentCacheManager cacheManager; /** * 配置CacheManager */ @PostConstruct public void init() { cacheManager= CacheManagerBuilder.newCacheManagerBuilder() // 持久化到磁盘的路径 .with(CacheManagerBuilder.persistence("../temp")) //立即初始化 .build(true); } /** * 创建并配置名为 "localCache" 的缓存 * @return localCache 缓存实例 */ @Bean public Cache<String, String> localCache() { // 创建并配置缓存 "myCache" return cacheManager.createCache("localCache", //设置key和value的类型 CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class, // 设置堆内存大小为100个条目 ResourcePoolsBuilder.heap(100))); } }
-
XML方式配置
在xml配置文件中我们手动配置一个Cache
<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/v3/schema/ehcache-config-3.0.xsd"> <!-- 缓存配置 --> <cache alias="myCache"> <key-type>java.lang.String</key-type> <value-type>java.lang.String</value-type> <!-- 使用条目数配置堆内存大小 --> <heap unit="entries">100</heap> </cache> </config>
获取xml并初始化
import org.ehcache.Cache; import org.ehcache.core.EhcacheManager; import org.ehcache.xml.XmlConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; /** * @author normaling */ @Configuration public class EhcacheConfig { //直接使用这个实现类更方便 private EhcacheManager cacheManager; /** * 配置CacheManager,从XML文件加载配置 */ @PostConstruct public void init() { // 从 XML 配置文件创建 CacheManager XmlConfiguration xmlConfig = new XmlConfiguration(getClass().getResource("/ehcache.xml")); cacheManager=new EhcacheManager(xmlConfig); cacheManager.init(); } /** * 获取并配置名为 "localCache" 的缓存 * @return myCache 缓存实例 */ @Bean public Cache<String, String> localCache() { // 从 CacheManager 获取已定义的缓存 return cacheManager.getCache("localCache", String.class, String.class); } }
-
-
对Cache进行crud操作
@Slf4j @SpringBootTest class SpringBoot2DemoApplicationTests { @Autowired private Cache<String, String> localCache; @Test void testCache() { localCache.put("key", "value"); //查询key String s = localCache.get("key"); System.out.println(s); //多次多同一个key进行put就会更新 localCache.put("key", "value2"); //删除key localCache.remove("key"); } }
三,xml配置模板
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.ehcache.org/v3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core-3.10.xsd">
<!--持久化存储的目录-->
<persistence directory="..\temp"/>
<!--cache-template:缓存设置模板-->
<cache-template name="default">
<!--key的类型-->
<key-type>java.lang.String</key-type>
<!--value的类型-->
<value-type>java.lang.String</value-type>
<!--缓存过期配置-->
<expiry>
<!--tti:缓存中条目的最大空闲时间-->
<!--ttl:缓存中条目的最大存活时间-->
<!--ttl和tti只能配置一个-->
<!--<tti unit="minutes">5</tti>-->
<ttl unit="seconds">30</ttl>
</expiry>
<!--资源配置-->
<resources>
<!--堆内存配置-->
<heap unit="entries">10</heap>
<!--堆外存配置-->
<offheap unit="MB">20</offheap>
<!--磁盘配置,persistence:是否持久化-->
<disk persistent="true" unit="MB">50</disk>
</resources>
</cache-template>
<!--创建本地缓存,并且直接调用缓存模板的内容-->
<cache alias="localCache" uses-template="default">
</cache>
</config>
四,API配置模板
4.1 方式一
@Configuration
public class EhcacheConfig {
private PersistentCacheManager cacheManager;
/**
* 配置CacheManager
*/
@PostConstruct
public void init() {
// 创建Ehcache CacheManager
cacheManager= CacheManagerBuilder.newCacheManagerBuilder()
// 持久化到磁盘的路径
.with(CacheManagerBuilder.persistence("../temp"))
//立即初始化
.build(true);
}
/**
* 创建并配置名为 "localCache" 的缓存
* @return myCache 缓存实例
*/
@Bean
public Cache<String, String> localCache() {
//创建缓存存储配置
ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder()
// 堆内存缓存
.heap(10)
// 堆内外存缓存
.offheap(20, MemoryUnit.MB)
// 磁盘缓存
.disk(30, MemoryUnit.MB, true)
.build();
// 创建缓存配置
CacheConfiguration<String, String> cacheConfiguration = CacheConfigurationBuilder
//配置缓存key,value的类型和缓存的保存大小
.newCacheConfigurationBuilder(String.class, String.class, resourcePools)
//配置缓存过期策略tti
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(100)))
//配置缓存过期策略ttl
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(500)))
.build();
return cacheManager.createCache("localCache", cacheConfiguration);
}
}
4.2 方式二
/**
* 本地Ehcache配置
* @author normaling
*/
@Slf4j
@Configuration
public class EhcacheConfig {
private PersistentCacheManager cacheManager;
/**
* 配置CacheManager
*/
@PostConstruct
public void init() {
// 创建Ehcache CacheManager
cacheManager= CacheManagerBuilder.newCacheManagerBuilder()
// 持久化到磁盘的路径
.with(CacheManagerBuilder.persistence("../temp"))
//立即初始化
.build(true);
}
/**
* 创建并配置名为 "localCache" 的缓存
* @return localCache 缓存实例
*/
@Bean
public Cache<String, String> localCache() {
return cacheManager.createCache("localCache", cacheConfiguration(String.class, String.class));
}
/**
* 通用默认的缓存配置
* @param keyType 缓存的key类型
* @param valueType 缓存value类型
*/
private <K,V> CacheConfiguration<K, V> cacheConfiguration(Class<K> keyType, Class<V> valueType) {
ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder()
// 堆内存缓存
.heap(10)
// 堆内外存缓存
.offheap(20, MemoryUnit.MB)
// 磁盘缓存, 磁盘缓存需要持久化到磁盘
.disk(30, MemoryUnit.MB, true)
.build();
return CacheConfigurationBuilder
//缓存过期策略二选一
.newCacheConfigurationBuilder(keyType, valueType, resourcePools)
// 缓存过期策略,缓存中条目的最大空闲时间
// .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(100)))
// 缓存过期策略,缓存中条目的最大生命周期
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(500)))
.build();
}
}
五,配置常见错误
- 在Ehcache中,通常
heap
(堆内存)应该比offheap
(堆外内存)小。因为offheap
内存一般是用于存储从heap
中溢出的缓存条目。如果heap
比offheap
大,Ehcache就无法正常工作。 heap
的配置大小应该小于disk
的配置大小。Ehcache 要求缓存的层次结构从小到大,即堆内存(heap)应该小于堆外内存(offheap),而堆外内存应小于磁盘缓存(disk)。- 不能将CacheManager交给Spring管理,这样会导致在关闭时Spring会销毁两次,会导致报错,这个是Ehcache3出现的问题