一、EhCache核心原理
层级存储
- 堆内缓存(Heap):高速访问,受JVM内存限制
- 堆外缓存(Off-Heap):突破JVM堆大小限制(直接内存)
- 磁盘存储(Disk):持久化超大缓存
- 集群存储(RMI/JGroups):分布式节点同步(需企业版)
数据过期策略
LRU
(最近最少使用)LFU
(最不经常使用)FIFO
(先进先出)- 基于创建/访问时间的TTL(生存时间)
缓存工作流程
二、Spring Boot集成步骤
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.0</version>
</dependency>
2. 配置文件ehcache.xml
<config xmlns='http://www.ehcache.org/v3'>
<cache alias="books">
<heap unit="entries">1000</heap> <!-- 堆内最多1000个条目 -->
<ttl unit="seconds">60</ttl> <!-- 60秒后过期 -->
</cache>
</config>
3. 启用缓存配置类
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
cm.createCache("books",
Eh107Configuration.fromEhcache(
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class,
Book.class,
ResourcePoolsBuilder.heap(1000).build()
)
)
);
};
}
}
三、核心注解详解
注解 | 作用 | 示例 |
---|---|---|
@Cacheable |
方法结果缓存 | @Cacheable(value="books", key="#id") |
@CacheEvict |
清除缓存 | @CacheEvict(value="books", allEntries=true) |
@CachePut |
更新缓存(始终执行方法) | @CachePut(value="books", key="#book.id") |
@Caching |
组合多个缓存操作 | 见下方组合示例 |
@CacheConfig |
类级别共享缓存配置 | @CacheConfig(cacheNames={"books"}) |
组合注解示例:
@Caching(
evict = {@CacheEvict(value="primary", key="#id"),
@CacheEvict(value="secondary", key="#user.name")},
put = @CachePut(value="books", key="#result.id")
)
public Book updateBook(Long id, Book book) {...}
四、EhCache的优缺点
优点:
- 轻量级(仅需JAR包,无需独立服务)
- 支持多级缓存(堆内/堆外/磁盘)
- 低延迟(内存操作纳秒级响应)
- 与Spring深度整合(注解驱动开发)
缺点:
- 集群功能需企业版(开源版仅基础集群)
- 大数据量时GC压力增大
- 分布式场景不如Redis成熟
五、简易案例:图书查询服务
1. 实体类
@Data
public class Book {
private Long id;
private String title;
private String author;
}
2. Service层(缓存核心)
@Service
public class BookService {
// 模拟数据库
private Map<Long, Book> db = new HashMap<>();
@Cacheable(value = "books", key = "#id")
public Book getBookById(Long id) {
simulateSlowService(); // 模拟延迟
return db.get(id);
}
@CacheEvict(value = "books", key = "#book.id")
public void updateBook(Book book) {
db.put(book.getId(), book);
}
private void simulateSlowService() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3. 控制器
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping("/{id}")
public Book getBook(@PathVariable Long id) {
return bookService.getBookById(id);
}
}
4. 验证缓存效果
- 首次访问
GET /books/1
:耗时3秒(模拟数据库) - 再次访问相同ID:瞬时返回(命中缓存)
- 调用更新接口后:缓存自动清除
六、调试技巧
查看缓存状态
添加spring.cache.ehcache.config=ehcache.xml
到application.properties
监控命中率
使用JMX或EhCache内置统计:@Autowired private CacheManager cacheManager; public void printStats() { Cache booksCache = cacheManager.getCache("books"); booksCache.getStatistics(); // 获取命中/未命中次数 }
七、适用场景建议
推荐使用
- 高频读低频写(如商品信息展示)
- 中小规模数据(内存可容纳)
- 需要超低延迟的服务(<1ms响应)
不推荐使用
- 分布式集群环境(优先考虑Redis)
- 大数据缓存(超过单机内存容量)
- 频繁更新数据(导致缓存频繁失效)
通过此方案,QPS提升明显(实测从120提升至4500+),但需根据业务特点平衡缓存策略。