Ehcache
Ehcache 是 Java 生态最成熟的进程内缓存框架,实现 JSR-107(JCache) 标准,Hibernate 默认使用其作为二级缓存(L2 Cache)。3.x 版本支持堆内(Heap)、堆外(Off-Heap)、磁盘(Disk)三层存储,适合缓存大量数据且不希望增加 GC 压力的场景。
适合:Hibernate L2 Cache、会话缓存、本地大对象缓存;分布式场景优先选 Redis。
三层存储模型
L1: Heap(JVM 堆) ← 最快,受 GC 影响,容量小
│ 溢出
▼
L2: Off-Heap(堆外) ← 较快,不受 GC 影响,需序列化
│ 溢出
▼
L3: Disk(磁盘) ← 最慢,容量最大,持久化
写入数据时先放 Heap,热点数据留在 Heap,冷数据下沉到 Off-Heap / Disk,淘汰时按配置策略(LRU / LFU / FIFO)驱逐。
快速上手
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>编程式配置
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("userCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, User.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(1000, EntryUnit.ENTRIES) // L1:堆内 1000 条
.offheap(100, MemoryUnit.MB) // L2:堆外 100MB
.disk(1, MemoryUnit.GB, true) // L3:磁盘 1GB,true=持久化
)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30)))
.withLoaderWriter(new UserCacheLoaderWriter()) // 读穿/写穿
)
.build(true); // true = 立即初始化
Cache<Long, User> userCache = cacheManager.getCache("userCache", Long.class, User.class);
userCache.put(1L, new User(1L, "Alice"));
User user = userCache.get(1L); // 命中返回,未命中 LoaderWriter 加载
userCache.remove(1L);XML 配置(ehcache.xml)
<config xmlns="http://www.ehcache.org/v3">
<cache alias="userCache">
<key-type>java.lang.Long</key-type>
<value-type>com.example.User</value-type>
<expiry>
<ttl unit="minutes">30</ttl>
</expiry>
<resources>
<heap unit="entries">1000</heap>
<offheap unit="MB">100</offheap>
<disk persistent="true" unit="GB">1</disk>
</resources>
</cache>
</config>Spring Boot 集成(JCache / JSR-107)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<classifier>jakarta</classifier> <!-- Spring Boot 3.x 用 Jakarta 版 -->
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>spring:
cache:
type: jcache
jcache:
config: classpath:ehcache.xml@Configuration
@EnableCaching
public class CacheConfig {}@Cacheable(value = "userCache", key = "#id")
public User getUser(Long id) {
return userRepository.findById(id).orElseThrow();
}
@CachePut(value = "userCache", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
@CacheEvict(value = "userCache", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}读穿 / 写穿(CacheLoaderWriter)
public class UserCacheLoaderWriter implements CacheLoaderWriter<Long, User> {
@Autowired
private UserRepository userRepository;
@Override
public User load(Long key) {
// 缓存 miss 时自动从 DB 加载
return userRepository.findById(key).orElse(null);
}
@Override
public void write(Long key, User value) {
// put 时同步写入 DB(写穿)
userRepository.save(value);
}
@Override
public void delete(Long key) {
userRepository.deleteById(key);
}
@Override
public Map<Long, User> loadAll(Iterable<? extends Long> keys) {
List<Long> ids = StreamSupport.stream(keys.spliterator(), false)
.collect(Collectors.toList());
return userRepository.findAllById(ids).stream()
.collect(Collectors.toMap(User::getId, u -> u));
}
}Hibernate L2 Cache 集成
<!-- pom.xml -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
</dependency>spring:
jpa:
properties:
hibernate:
cache:
use_second_level_cache: true
use_query_cache: true
region.factory_class: jcache
javax.cache.provider: org.ehcache.jsr107.EhcacheCachingProvider
javax.cache.uri: classpath:ehcache.xml@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // 开启实体二级缓存
public class User { ... }缓存事件监听
CacheEventListenerConfigurationBuilder listener =
CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(
event -> log.info("事件: {} key={}", event.getType(), event.getKey()),
EventType.CREATED, EventType.UPDATED, EventType.EXPIRED, EventType.EVICTED
)
.asynchronous() // 异步触发,不影响主流程
.unordered();Ehcache vs Caffeine
| 特性 | Ehcache 3 | Caffeine |
|---|---|---|
| 多层存储 | 堆 + 堆外 + 磁盘 | 仅堆内 |
| 持久化 | 支持(磁盘层) | 不支持 |
| JSR-107 | 完整实现 | 需适配层 |
| Hibernate L2 | 官方支持 | 需额外适配 |
| 淘汰算法 | LRU / LFU / FIFO | W-TinyLFU(命中率更高) |
| 性能(纯堆内) | 略低 | 更高 |
| 适用场景 | 大对象、持久化、Hibernate | 高频小对象、本地热点缓存 |