# 缓存之 Ehcache
# 简介
Ehcache 是一个功能强大的 Java 缓存库,它提供了丰富的缓存策略和灵活的配置选项。本指南将详细介绍如何使用 Ehcache 以及如何将其与 Spring Boot 集成。
# 什么是 Ehcache?
Ehcache 是一个开源的 Java 缓存,它旨在降低系统负载、提高响应速度,并且可以减少对后端数据源(如数据库)的访问。Ehcache 支持多种缓存策略,如 LRU(最近最少使用)、FIFO(先进先出)等。
# Ehcache 的主要特点
- 简单易用:提供简单直观的 API。
- 可扩展性:支持集群,可进行分布式缓存。
- 多种缓存策略:支持多种缓存逐出算法。
- 缓存监听:可以监听缓存项的创建、更新和删除。
- 缓存数据持久化:支持将缓存数据写入磁盘。
# 同样都是缓存 redis 和 ehcache 哪个更好呢?
# Redis
- 内存数据库:Redis 是一个开源的内存中数据结构存储系统,它可以用作数据库、缓存和消息代理。
- 丰富的数据类型:Redis 支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。
- 持久化:Redis 支持数据的持久化,可以通过 RDB 和 AOF 两种方式将内存中的数据保存到磁盘中。
- 分布式:Redis 支持集群模式,能够实现数据的分片和复制,提高缓存的容量和可用性。
- 高并发:Redis 能够处理大量的并发请求,适合需要高并发读写的应用场景。
- 功能丰富:Redis 不仅可以作为缓存使用,还可以作为消息队列、排行榜、实时分析等场景的数据存储。
# Ehcache
- Java 进程内缓存:Ehcache 是一个纯 Java 的进程内缓存框架,简单易用。
- 内存和磁盘存储:Ehcache 支持在内存和磁盘上存储缓存数据,具有两级缓存机制。
- 多种缓存策略:Ehcache 提供了多种缓存策略,如 LRU(最近最少使用)、FIFO(先进先出)等。
- 分布式缓存:Ehcache 可以通过 RMI、可插入 API 等方式实现分布式缓存(比较麻烦)。
- 缓存监听:Ehcache 支持缓存和缓存管理器的侦听接口,可以监听缓存项的创建、更新和删除。
- Hibernate 缓存实现:Ehcache 是 Hibernate 的默认缓存提供者,适合与 Hibernate 集成使用。
# 哪个更好?
选择 Redis 还是 Ehcache 取决于具体的应用场景和需求:
- 如果你需要一个功能丰富、支持多种数据结构和持久化的内存数据库,并且可以处理高并发请求,那么 Redis 可能是更好的选择。
- 如果你需要一个简单、轻量级的 Java 进程内缓存,或者需要与 Hibernate 集成,那么 Ehcache 可能更适合你的需求。
总的来说,两者各有千秋,没有绝对的 “更好”,只有更适合特定场景的解决方案。在实际应用中,有时也会将两者结合使用,以发挥各自的优势。
也就说,我只需要简单的缓存,加快查询并且只是单机环境下,那么使用 Ehcache 就够了。 如果需要复杂的缓存结构,或者是在分布式环境下就可以考虑 redis
# 扩展
其实还可以使用 spring 自带缓存框架(用法可下面的一样,只是不需要加配置,只需要在启动类加相同的注解,使用注解的方式缓存)
spring-context-5.2.15.RELEASE.jar
在 org.springframework.cache.* 包下
# Ehcache 整合 spring boot
# 1. 添加依赖
首先,需要在项目的 pom.xml
文件中添加 Ehcache 的依赖。
<dependencies> | |
<!-- Spring Boot Starter Cache --> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-cache</artifactId> | |
</dependency> | |
<!-- Ehcache --> | |
<dependency> | |
<groupId>org.ehcache</groupId> | |
<artifactId>ehcache</artifactId> | |
<version>3.9.2</version> | |
</dependency> | |
</dependencies> |
# 2. 配置 Ehcache
在 src/main/resources
目录下创建一个 Ehcache 配置文件,例如 ehcache.xml
。
<?xml version="1.0" encoding="UTF-8"?> | |
<ehcache> | |
<!-- | |
磁盘的缓存位置 | |
磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于 Windows 系统的虚拟内存 | |
path: 指定在硬盘上存储对象的路径 | |
path 可以配置的目录有: | |
user.home(用户的家目录) | |
user.dir(用户当前的工作目录) | |
java.io.tmpdir(默认的临时目录) | |
ehcache.disk.store.dir(ehcache 的配置目录) | |
绝对路径(如:d:\\ehcache) | |
查看路径方法:String tmpDir = System.getProperty ("java.io.tmpdir"); | |
--> | |
<diskStore path="D:\EhCache"/> | |
<!-- 默认缓存 --> | |
<defaultCache | |
maxEntriesLocalHeap="10000" | |
eternal="false" | |
timeToIdleSeconds="120" | |
timeToLiveSeconds="120" | |
maxEntriesLocalDisk="10000000" | |
diskExpiryThreadIntervalSeconds="120" | |
memoryStoreEvictionPolicy="LRU"> | |
<persistence strategy="localTempSwap"/> | |
</defaultCache> | |
<!--helloworld 缓存 --> | |
<cache name="HelloWorldCache" | |
maxElementsInMemory="1000" | |
eternal="false" | |
timeToIdleSeconds="5" | |
timeToLiveSeconds="5" | |
overflowToDisk="false" | |
memoryStoreEvictionPolicy="LRU"/> | |
<!-- | |
defaultCache:默认缓存策略,当 ehcache 找不到定义的缓存时,则使用这个 | |
缓存策略。只能定义一个。 | |
--> | |
<!-- | |
name: 缓存名称。 | |
maxElementsInMemory: 缓存最大数目 | |
maxElementsOnDisk:硬盘最大缓存个数。 | |
eternal: 对象是否永久有效,一但设置了,timeout 将不起作用。 | |
overflowToDisk: 是否保存到磁盘,当系统宕机时 | |
timeToIdleSeconds: 设置对象在失效前的允许闲置时间(单位:秒)。仅当 | |
eternal=false 对象不是永久有效时使用,可选属性,默认值是 0,也就是可闲置时间无穷大。 | |
timeToLiveSeconds: 设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当 eternal=false 对象不是永久有效时使用, | |
默认是 0.,也就是对象存活时间无穷大。 | |
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store | |
persists between restarts of the Virtual Machine. The default value is false. | |
diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个 Cache 都应该有自己的一个缓冲区。 | |
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒。 | |
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时, | |
Ehcache 将会根据指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先出)或是 LFU(较少使用)。 | |
clearOnFlush:内存数量最大时是否清除。 | |
memoryStoreEvictionPolicy: 可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。 | |
FIFO,first in first out,这个是大家最熟的,先进先出。 | |
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个 hit 属性,hit 值最小的将 | |
会被清出缓存。 | |
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳 | |
离当前时间最远的元素将被清出缓存。 | |
--> | |
</ehcache> |
# 3. application.yml
spring: | |
cache: | |
type: ehcache | |
ehcache: | |
config: classpath:ehcache.xml |
# 4. spring boot 启动类开启缓存注解
@SpringBootApplication | |
@EnableCaching | |
public class MyApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(MyApplication.class, args); | |
} | |
} |
# 5. 使用 Ehcache
在需要缓存的组件中注入 CacheManager
并使用它来获取缓存。
import org.ehcache.Cache; | |
import org.ehcache.CacheManager; | |
import org.springframework.stereotype.Service; | |
@Service | |
public class CacheService { | |
private final Cache<String, Object> cache; | |
public CacheService(CacheManager cacheManager) { | |
this.cache = cacheManager.getCache("myCache", String.class, Object.class); | |
} | |
public Object getFromCache(String key) { | |
return cache.get(key); | |
} | |
public void putToCache(String key, Object value) { | |
cache.put(key, value); | |
} | |
} |
# 6. 缓存注解
Ehcache 也支持使用注解来简化缓存逻辑。
import org.ehcache.Cache; | |
import org.springframework.cache.annotation.Cacheable; | |
import org.springframework.stereotype.Service; | |
@Service | |
public class MyService { | |
@Cacheable(cacheNames = "myCache", key = "#id") | |
public Object getDataById(String id) { | |
// 模拟耗时操作 | |
return "Data for " + id; | |
} | |
} |
# 实际使用场景
# 场景一:缓存数据库查询结果
假设有一个方法用于从数据库获取用户信息,我们可以使用 Ehcache 来缓存这些查询结果。
@Cacheable(value = "userCache", key = "#userId") | |
public User findUserById(Long userId) { | |
// 数据库查询逻辑 | |
return userRepository.findById(userId).orElse(null); | |
} |
# 场景二:缓存 Web 页面
对于不经常变化的 Web 页面,可以使用 Ehcache 来缓存页面内容。
@Controller | |
public class PageController { | |
@Cacheable(cacheNames = "pageCache", key = "#pageName") | |
public String showPage(String pageName) { | |
// 页面渲染逻辑 | |
return "page"; | |
} | |
} |
# 场景三:缓存计算结果
对于计算密集型的操作,可以使用 Ehcache 来缓存结果,避免重复计算。
@Cacheable(value = "computationCache", key = "#input") | |
public double computeValue(String input) { | |
// 复杂的计算逻辑 | |
return computeResult(input); | |
} |
# 总结
Ehcache 是一个功能丰富的缓存框架,它可以显著提高应用程序的性能。通过与 Spring Boot 的集成,可以轻松地在应用程序中实现缓存逻辑。根据实际业务需求选择合适的缓存策略,可以有效地减少系统负载和提高响应速度。
# 参考资料
- Ehcache 官方文档