目录
- Ehcache 简介
- 准备工作:添加依赖
- 核心概念
- 快速上手:基础用法
- 高级特性
- 缓存配置文件 (
ehcache.xml) - 缓存过期策略
- 缓存事件监听
- 缓存配置文件 (
- Ehcache 3 vs Ehcache 2.x
- 完整示例
- 最佳实践
Ehcache 简介
Ehcache 的主要特点:

- 高性能:采用多种优化策略,读写性能优异。
- 标准兼容:完全遵循 JSR-107 (JCache) 标准,具有良好的可移植性。
- 功能丰富:支持堆内缓存、堆外缓存、磁盘持久化、集群同步、分布式缓存等。
- 灵活配置:可以通过 XML、代码或注解进行配置。
- 多版本:Ehcache 3 是基于 JSR-107 重新设计的现代化版本,而 Ehcache 2.x 是一个更传统的、功能强大的版本,两者 API 和配置方式不兼容。
准备工作:添加依赖
根据你使用的构建工具(Maven 或 Gradle),在 pom.xml 或 build.gradle 文件中添加 Ehcache 3 的核心依赖。
Maven (pom.xml)
<dependencies>
<!-- Ehcache 3 核心库 -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version> <!-- 建议使用最新稳定版 -->
</dependency>
<!-- 为了支持 JSR-107 API (CachingProvider, CacheManager, Cache 等) -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
Gradle (build.gradle)
dependencies {
// Ehcache 3 核心库
implementation 'org.ehcache:ehcache:3.10.8' // 建议使用最新稳定版
// 为了支持 JSR-107 API
implementation 'javax.cache:cache-api:1.1.1'
}
核心概念
在使用 Ehcache 之前,了解以下几个核心 JSR-107 接口非常重要:
CachingProvider:缓存提供者,负责创建和管理CacheManager,一个 JVM 中可以有多个CachingProvider。CacheManager:缓存管理器,负责创建、配置、管理和销毁Cache实例,一个CacheManager可以管理多个Cache。Cache<K, V>:缓存,一个命名的、强类型的、线程安全的对象存储区域,它是你与缓存进行交互的主要接口。Entry<K, V>:缓存条目,存储在缓存中的键值对。
标准的获取缓存对象的流程是:
CachingProvider -> CacheManager -> Cache
快速上手:基础用法
最简单的方式是使用 CacheManagerBuilder 以编程方式创建缓存。

示例代码
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.expiry.ExpiryPolicy;
public class EhcacheQuickStart {
public static void main(String[] args) throws InterruptedException {
// 1. 创建 CacheManager
// 使用 CacheManagerBuilder 创建一个临时的、基于堆的 CacheManager
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
cacheManager.init(); // 初始化 CacheManager
// 2. 定义并创建 Cache
// 缓存名为 "userCache"
// 键类型为 Long,值类型为 String
// 设置缓存池为堆内存,最大存放 200 个元素
Cache<Long, String> userCache = cacheManager.createCache("userCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, // 键类型
String.class, // 值类型
ResourcePoolsBuilder.heap(200) // 缓存池配置:堆内存,200个元素
));
// 3. 使用 Cache
// 放入数据
userCache.put(1L, "Alice");
userCache.put(2L, "Bob");
// 获取数据
String user1 = userCache.get(1L);
System.out.println("User with id 1: " + user1); // 输出: User with id 1: Alice
// 检查是否存在
boolean exists = userCache.containsKey(2L);
System.out.println("User with id 2 exists: " + exists); // 输出: User with id 2 exists: true
// 删除数据
userCache.remove(1L);
System.out.println("User with id 1 after removal: " + userCache.get(1L)); // 输出: User with id 1 after removal: null
// 4. 关闭 CacheManager
// 关闭后会释放所有资源
cacheManager.close();
}
}
高级特性
1 缓存配置文件 (ehcache.xml)
对于复杂的缓存配置,推荐使用 XML 文件,而不是硬编码在 Java 代码中。
-
在
src/main/resources目录下创建ehcache.xml文件。 -
ehcache.xml示例:<?xml version="1.0" encoding="UTF-8"?> <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/ehcache.xsd"> <!-- 定义服务,用于指定堆外和磁盘存储的位置 --> <service> <persistence directory="java.io.tmpdir/ehcache-persistence"/> </service> <!-- 定义一个缓存 --> <cache alias="userCache"> <!-- 键、值序列化方式 --> <key-type>java.lang.Long</key-type> <value-type>java.lang.String</value-type> <!-- 缓存池配置 --> <!-- heap: 堆内存 --> <!-- offheap: 堆外内存 --> <!-- disk: 磁盘持久化 --> <resources> <heap unit="entries">200</heap> <!-- 当堆内存满时,可以将 100MB 的数据存入堆外内存 --> <offheap unit="MB">100</offheap> <!-- 当堆外内存也满时,可以将 500MB 的数据持久化到磁盘 --> <disk unit="MB">500</disk> </resources> <!-- 过期策略 --> <expiry> <!-- 创建后 10 分钟过期 --> <ttl unit="minutes">10</ttl> </expiry> </cache> <!-- 再定义一个简单的缓存 --> <cache alias="simpleCache"> <key-type>java.lang.String</key-type> <value-type>java.lang.Integer</value-type> <resources> <heap unit="entries">500</heap> </resources> </cache> </config> -
在 Java 代码中使用配置文件:
(图片来源网络,侵删)// 使用配置文件创建 CacheManager CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() .with(CacheManagerBuilder.persistence("path/to/your/cache/store")) // 指定持久化目录 .build(true); // build(true) 会自动初始化 // 获取已配置的缓存 Cache<Long, String> userCache = cacheManager.getCache("userCache", Long.class, String.class); Cache<String, Integer> simpleCache = cacheManager.getCache("simpleCache", String.class, Integer.class); // ... 使用缓存 ... cacheManager.close();
2 缓存过期策略
Ehcache 支持多种过期策略,可以在配置文件或代码中指定:
timeToIdle(TTI):一个条目在被访问后,多长时间内没有被再次访问,则过期。timeToLive(TTL):一个条目从创建开始,多长时间后过期,无论是否被访问。no expiry:永不过期。
可以在 ehcache.xml 的 <expiry> 标签中配置:
<expiry>
<!-- TTL: 创建后60秒过期 -->
<ttl unit="seconds">60</ttl>
<!-- 或者 TTI: 被访问后60秒未再次访问则过期 -->
<!-- <tti unit="seconds">60</tti> -->
</expiry>
3 缓存事件监听
你可以为缓存添加监听器,在条目被创建、更新、删除或过期时执行自定义逻辑。
-
创建监听器类:
import javax.cache.event.CacheEntryEvent; import javax.cache.event.CacheEntryListenerException; import javax.cache.event.CacheEntryUpdatedListener; import java.util.EventListener; public class MyCacheListener implements CacheEntryUpdatedListener<Long, String> { @Override public void onUpdated(Iterable<CacheEntryEvent<? extends Long, ? extends String>> events) throws CacheEntryListenerException { for (CacheEntryEvent<? extends Long, ? extends String> event : events) { System.out.println("Cache Event: Key " + event.getKey() + " was updated from '" + event.getOldValue() + "' to '" + event.getValue() + "'"); } } } -
注册监听器:
你可以在创建缓存配置时添加监听器。
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(); cacheManager.init(); Cache<Long, String> userCache = cacheManager.createCache("userCache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(200)) .withEventFiltering() // 启用事件过滤 .withEventListeners(new MyCacheListener()) // 添加监听器 ); userCache.put(1L, "Alice"); userCache.put(1L, "Alice Smith"); // 这会触发更新事件 cacheManager.close();
Ehcache 3 vs Ehcache 2.x
| 特性 | Ehcache 3 | Ehcache 2.x |
|---|---|---|
| 标准 | 完全遵循 JSR-107 (JCache) 标准 | 不完全遵循 JSR-107,有自己的 API |
| API | 使用 JSR-107 接口 (Cache, CacheManager) 和 CacheManagerBuilder |
使用 CacheManager, Cache 等自己定义的类 |
| 配置 | 优先使用 ehcache.xml,支持 JSR-107 的 @CacheResult 等注解 |
优先使用 ehcache.xml,有自己的 @Cacheable 等注解 (Spring Cache 集成时) |
| 存储层 | 更灵活,支持堆、堆外、磁盘的多层存储 | 支持堆、磁盘、集群 |
| 集群 | 通过 Terracotta 客户端实现 | 通过 Terracotta 服务器实现,非常成熟 |
| 推荐 | 新项目推荐使用,现代化,标准,易于集成 | 旧项目或需要 Terracotta 集群特性的项目 |
简单来说:如果你现在开始一个新项目,请直接选择 Ehcache 3,它更符合行业标准,API 更现代化,如果你维护的是一个老项目,并且正在使用 Ehcache 2.x,那么可以继续使用,但升级到 3.x 需要做较多工作。
完整示例 (结合配置文件和事件监听)
这个例子演示了如何加载 ehcache.xml,创建一个带过期策略和监听器的缓存,并进行操作。
src/main/resources/ehcache.xml(同上)src/main/java/com/example/MyCacheListener.java(同上)MainApp.java
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;
import javax.cache.configuration.Factory;
import java.net.URL;
public class MainApp {
public static void main(String[] args) throws InterruptedException {
// 1. 从类路径加载 ehcache.xml 配置文件
URL myUrl = getClass().getResource("/ehcache.xml");
XmlConfiguration xmlConfig = new XmlConfiguration(myUrl);
// 2. 使用配置文件创建 CacheManager
CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig).build(true);
// 3. 获取已配置的缓存
Cache<Long, String> userCache = cacheManager.getCache("userCache", Long.class, String.class);
// 4. 使用缓存
System.out.println("Putting user 101...");
userCache.put(101L, "Charlie");
System.out.println("Got user 101: " + userCache.get(101L)); // 应该输出 Charlie
System.out.println("Updating user 101...");
userCache.put(101L, "Charles"); // 这会触发 MyCacheListener 的 onUpdated 方法
// 5. 测试过期策略 (TTL为10分钟,这里我们等待一小会儿来观察)
// 注意:TTL 的检查不是实时的,通常在访问或写入时才会触发
System.out.println("Waiting for 1 second to test TTL (though TTL is 10 mins, this just shows the concept)...");
Thread.sleep(1000);
System.out.println("Got user 101 after 1 sec: " + userCache.get(101L)); // 仍然存在
// 6. 关闭 CacheManager
cacheManager.close();
}
}
最佳实践
- 选择合适的版本:新项目使用 Ehcache 3。
- 使用配置文件:将缓存配置(如大小、过期策略、存储层)与业务代码分离,使用
ehcache.xml。 - 明确键和值类型:在创建缓存时,始终明确指定键和值的类型,以保证类型安全。
- 设置合理的缓存大小:根据应用内存和业务数据量,为
heap缓存设置一个合理的上限,避免OutOfMemoryError。 - 配置合适的过期策略:为缓存数据设置 TTL 或 TTI,防止缓存中堆积过期的“僵尸数据”。
- 始终关闭
CacheManager:在应用生命周期结束时(如 Web 应用的ServletContextListener的contextDestroyed方法中),调用cacheManager.close(),以释放所有资源,包括线程和文件句柄。 - 考虑集成 Spring Cache:如果你在使用 Spring Boot,可以非常方便地集成 Ehcache 作为
CacheManager实现,只需添加依赖和配置即可,无需手动操作CacheManager和Cache,这是目前最主流的使用方式。
