目录
- 1、Ehcache 简介
- 2、Ehcache 集群方式
- 3、工作原理
- 3.1、缓存写入
- 3.2、缓存查找
- 3.3、缓存过期和驱逐
- 3.4、缓存持久化
- 4、入门案例 —— Ehcache 2.x 版本
- 4.1、单独使用 Ehcache
- 4.1.1、引入依赖
- 4.1.2、配置 Ehcache
- 4.1.2.1、XML 配置方式
- 4.1.2.1.1、新建 ehcache.xml
- 4.1.2.1.2、使用 Ehcache
- 4.1.2.2、API 配置方式
- 4.1.2.2.1、添加一个配置类
- 4.1.2.2.2、使用 Ehcache
- 5、入门案例 —— Ehcache 3.x 版本
- 5.1、单独使用 Ehcache
- 5.1.1、引入依赖
- 5.1.2、配置 Ehcache
- 5.1.2.1、XML 文件配置
- 5.1.2.1.1、新建 ehcache.xml 文件
- 5.1.2.1.2、使用 Ehcache
- 5.1.2.2、API 配置
- 5.1.2.2.1、新建一个配置类
- 5.1.2.2.2、使用 EhCache
- 5.1.2.2.3、EhCache 数据存储位置
- 5.1.2.2.4、数据生存时间
- 5.2、在 SpringBoot 中使用 Ehcache
- 5.2.1、引入依赖
- 5.2.2、配置 Ehcache
- 5.2.2.1、XML 配置文件
- 5.2.2.1.1、新建一个配置文件
- 5.2.2.1.2、启动类开启缓存注解
- 5.2.2.1.3、添加配置类
- 5.2.2.1.4、使用 Ehcache
- 5.2.2.2、API 配置
- 5.2.2.2.1、新建一个配置类
- 5.2.2.2.2、使用 Ehcache
- 5.3、集成 Spring Cache
- 5.3.1、引入依赖
- 5.3.2、启动类开启缓存注解
- 5.3.3、配置 Ehcache
- 5.3.3.1、添加配置信息
- 5.3.3.2、配置属性类
- 5.3.3.3、配置 CachaManager
- 5.3.4、使用 Ehcache
- 5.3.4.1、基于注解的缓存
- 5.3.4.1.1、新建一个 UserServiceImpl
- 5.3.4.1.2、新建一个 TestController
- 5.3.4.12、基于缓存管理器的编程方式
1、Ehcache 简介
EhCache
是一种广泛使用的开源 Java 分布式缓存。主要面向通用缓存、Java EE 和轻量级容器,可以和大部分 Java 项目无缝整合。
Ehcache
虽然也支持分布式模式,但是分布式方案不是很好,建议只将其作为单机的进程内缓存使用
特点:
- 直接在 JVM 虚拟机中缓存,速度快,效率高
- 支持多种缓存策略:LRU、LFU、FIFO 淘汰算法
- 支持内存和磁盘存储,默认存储在内存中,如内存不够时把缓存数据同步到磁盘中;
- 支持多缓存管理器实例,以及一个实例的多个缓存区域
- 支持基于 Filter 的 Cache 实现,也支持 Gzip 压缩算法
EhCache
可以单独使用,一般在第三方库中被用到的比较多【mybatis、shiro】;EhCache
对分布式支持不够好,多个节点通过组播方式同步,效率不高,通常和 Redis 一块使用【通过 RMI 或者 Jgroup 多播方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适】
2、Ehcache 集群方式
Ehcache 目前支持五种集群方式:
- RMI:使用组播方式通知所有节点同步数据。如果网络有问题,或某台服务宕机,则存在数据无法同步的可能,导致数据不一致。
- JMS。JMS 类似 MQ,所有节点订阅消息,当某节点缓存发生变化,就向 JMS 发消息,其他节点感知变化后,同步数据
- JGroup
- Terracotta
- Ehcache Server
3、工作原理
3.1、缓存写入
当应用程序向 Ehcache 中写入数据时,Ehcache 会首先检查该数据是否已经存在于缓存中。如果数据已经存在于缓存中,则更新该数据;否则,将该数据写入缓存。如下:
- 当应用程序请求写入一个数据项到 Ehcache 中时,这个数据项被传递给Ehcache API
- Ehcache 首先根据该数据项的键值对定位其对应的 Cache 对象
- Ehcache 根据配置中的缓存策略,比如是否应该在缓存中创建一个新的元素,以及新元素是否会淘汰老的元素
- 如果需要创建一个新缓存元素,则 Ehcache 创建一个新的元素并将其添加到 Cache 对象中
- 如果缓存中已经存在该元素,Ehcache 会根据缓存策略对该元素进行更新或替换
- Ehcache 将更新后的 Cache 对象返回给应用程序
3.2、缓存查找
当应用程序需要查询缓存中的数据时,Ehcache 首先会检查该数据是否存在于缓存中。如果数据存在于缓存中,则直接返回缓存数据;否则,从数据库或其他资源获取数据,并将其存入缓存中。如下:Ehcache 缓存查找的详细流程。
- 当应用程序请求从 Ehcache 中读取一个数据项时,这个请求被传递给 Ehcache API。
- Ehcache 首先根据该数据项的键值对定位其对应的 Cache 对象。
- Ehcache 检查该数据项是否已经存在于缓存中。
- 如果数据项存在于缓存中,Ehcache 可以直接将其返回给应用程序。
- 如果数据项不存在于缓存中,Ehcache 就需要从数据库或其他数据源(如文件、网络等)中获取数据。
- 获取到数据后,Ehcache 会将其添加到缓存中并返回给应用程序
3.3、缓存过期和驱逐
Ehcache 提供了多种缓存失效策略,例如基于时间的缓存失效、基于访问的缓存失效、基于大小的缓存失效等。当缓存数据过期或缓存空间不足时,Ehcache 会选择一部分缓存元素进行驱逐以腾出更多的内存空间。如下:
- Ehcache 会周期性地扫描缓存中的元素来标记那些已经过期的元素。
- Ehcache根据缓存策略(如基于时间、基于访问、基于大小等)判断哪些缓存元素应该被驱逐。
- 驱逐过程通常是异步执行的,Ehcache 会在后台线程上执行这个操作
3.4、缓存持久化
Ehcache 还提供了缓存持久化功能,它可以将缓存中的数据持久化到磁盘或者其他数据源。在应用程序重启或者缓存失效后,Ehcache 可以从持久化存储中恢复数据,从而保证数据的完整性和可靠性。如下:
- Ehcache 使用磁盘存储或数据库等持久化技术来存储缓存数据。
- 当缓存中的数据更新时,Ehcache 会自动将此数据持久化到持久化存储中。
- 在应用程序重启或者缓存失效后,Ehcache 会从持久化存储中读取缓存数据并重新加载到内存中
4、入门案例 —— Ehcache 2.x 版本
EhCache缓存框架
4.1、单独使用 Ehcache
4.1.1、引入依赖
<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.6</version>
</dependency>
4.1.2、配置 Ehcache
配置 Ehcache:用于定义缓存的行为和属性。
以下是一些主要用途:
- 缓存定义: 可以定义一个或多个缓存,包括它们的名称、存储策略(如内存、磁盘)、最大条目数等
- 过期策略: 你可以设置缓存条目的过期时间,如“时间到期”或“空闲时间”。这有助于控制缓存数据的生命周期
- 溢出到磁盘: 如果缓存超出了内存限制,可以配置将数据溢出到磁盘,以避免数据丢失
- 持久化选项: 配置是否需要将缓存数据持久化到文件系统,以便在应用重启后恢复缓存状态
- 性能优化: 可以为缓存设置特定的性能参数,以优化应用的缓存行为
配置 Ehcache 有两种方式,分别为 XML、API
4.1.2.1、XML 配置方式
4.1.2.1.1、新建 ehcache.xml
ehcache.xml
:是 EhCache 的配置文件。通过这个文件,可以指定多个缓存的设置以及全局的默认配置。
在 classpath
路径下新建 ehCache/ehcache.xml
文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache><!--磁盘的缓存位置磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存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/data"/><!--默认缓存--><!--defaultCache:默认缓存策略,当 ehcache 找不到定义的缓存时,则使用这个缓存策略。只能定义一个。--><defaultCachemaxEntriesLocalHeap="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxEntriesLocalDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><persistence strategy="localTempSwap"/></defaultCache><!--userCache 缓存--><!--name:缓存名称。maxElementsInMemory:缓存最大数目maxElementsOnDisk:硬盘最大缓存个数。eternal:对象是否永久有效,一但设置了,timeout 将不起作用。overflowToDisk:是否保存到磁盘,当系统宕机时timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当 eternal=false 对象不是永久有效时使用,可选属性,默认值是 0,也就是可闲置时间无穷大。timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当 eternal=false 对象不是永久有效时使用,默认是 0.,也就是对象存活时间无穷大。diskPersistent:是否缓存虚拟机重启期数据,默认为 falsediskSpoolBufferSizeMB:这个参数设置 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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。--><cache name="userCache"maxElementsInMemory="1000"eternal="false"timeToIdleSeconds="5"timeToLiveSeconds="5"overflowToDisk="false"memoryStoreEvictionPolicy="LRU"/>
</ehcache>
配置说明:
diskStore
:用于配置缓存的磁盘存储路径。所有被溢出到磁盘的缓存数据将会存储在这个目录中- 数据持久化:当内存中的缓存条目超过限制时,EhCache 会将一些条目溢出到指定的磁盘路径,以减少内存使用并保持应用性能
- 恢复能力:如果配置了持久化策略,可以在应用重启后从磁盘恢复缓存数据,确保数据不会丢失
defaultCache
:默认缓存策略。当Ecache
找不到定义的缓存时,则使用这个缓存策略。只能定义一个maxEntriesLocalHeap="10000"
:指定在本地内存(Heap)中可以存储的最大条目数。这里设置为 10000,表示最多可以存放 10,000 个缓存条目eternal="false"
:缓存条目是否永远有效。设置为 false,意味着条目会在指定的时间后失效timeToIdleSeconds="120"
:指定条目在不被访问的情况下可以保持有效的时间,单位为秒。如果条目在 120 秒内未被访问,将会被移除timeToLiveSeconds="120"
:指定条目从被创建开始到失效的总时间,单位为秒。如果条目在 120 秒后不论是否被访问都会被移除maxEntriesLocalDisk="10000000"
:指定在本地磁盘中可以存储的最大条目数。设置为 10000000,表示最多可以在磁盘上存放 10,000,000 个条目diskExpiryThreadIntervalSeconds="120"
:指定处理磁盘过期条目的线程运行的间隔,单位为秒。设置为 120,表示每 120 秒检查一次磁盘中的过期条目memoryStoreEvictionPolicy="LRU">
:指定内存存储的驱逐策略。在这里设置为 LRU(Least Recently Used),表示当内存达到最大容量时,会优先移除最近最少使用的条目persistence strategy="localTempSwap"
:用于配置缓存的持久化策略。strategy=“localTempSwap” 表示将缓存数据临时存储到本地磁盘,以防数据丢失,但不一定是永久存储
userCache
:
4.1.2.1.2、使用 Ehcache
public class Test {public static void main(String[] args) {// 获取 EhCache 的缓存管理对象CacheManager cacheManager = new CacheManager(Test.class.getClassLoader().getResourceAsStream("ehcache/ehcache.xml"));Cache cache = cacheManager.getCache("userCache");// 创建缓存数据Element element = new Element("name","zzc");// ① 存入缓存cache.put(element);// ② 从缓存中取出Element element1 = cache.get("name");System.out.println(element1.getObjectValue());// ③ 删除缓存boolean flag = cache.remove("name");if (flag) {System.out.println("删除成功");} else {// ④ 再次获取缓存数据element1 = cache.get("name");System.out.println(element1.getObjectValue());}cacheManager.shutdown();}
}
可以使用 put
、get
、remove
等方法进行缓存操作
4.1.2.2、API 配置方式
4.1.2.2.1、添加一个配置类
public class EhCacheConfig {private CacheManager cacheManager;public EhCacheConfig() {// 创建全局配置Configuration configuration = new Configuration();// 配置缓存CacheConfiguration cacheConfig = new CacheConfiguration("userCache", 1000) // 缓存名称和最大条目数.memoryStoreEvictionPolicy("LRU") // 驱逐策略.timeToLiveSeconds(300) // 存活时间.timeToIdleSeconds(300); // 空闲时间configuration.addCache(cacheConfig);// 初始化 CacheManagercacheManager = CacheManager.newInstance(configuration);}public Cache getCache(String cacheName) {return cacheManager.getCache(cacheName);}public void shutdown() {if (cacheManager != null) {cacheManager.shutdown();}}
}
4.1.2.2.2、使用 Ehcache
public class Test {public static void main(String[] args) {// 获取 EhCache 的缓存管理对象EhCacheConfig ehCacheConfig = new EhCacheConfig();Cache cache = ehCacheConfig.getCache("userCache");// 创建缓存数据Element element = new Element("name","zzc");// ① 存入缓存cache.put(element);// ② 从缓存中取出Element element1 = cache.get("name");System.out.println(element1.getObjectValue());// ③ 删除缓存boolean flag = cache.remove("name");if (flag) {System.out.println("删除成功");} else {// ④ 再次获取缓存数据element1 = cache.get("name");System.out.println(element1.getObjectValue());}ehCacheConfig.shutdown();}
}
5、入门案例 —— Ehcache 3.x 版本
5.1、单独使用 Ehcache
5.1.1、引入依赖
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.10.0</version>
</dependency>
5.1.2、配置 Ehcache
5.1.2.1、XML 文件配置
5.1.2.1.1、新建 ehcache.xml 文件
<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/schema/ehcache-core-3.0.xsd"><cache alias="userCache"><key-type>java.lang.Integer</key-type><value-type>java.lang.String</value-type><expiry><!-- 设置过期时间为 5 分钟 --><ttl unit="minutes">5</ttl> </expiry><resources><heap unit="entries">100</heap> <!-- 最大条目数 --></resources></cache>
</config>
定义了一个名为 userCache
的缓存,配置了键值类型、过期时间、最大存储数量等参数
5.1.2.1.2、使用 Ehcache
public class Test {public static void main(String[] args) {// 获取 EhCache 的缓存管理对象XmlConfiguration xmlConfig = new XmlConfiguration(Test.class.getResource("/ehcache/ehcache.xml"));CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);cacheManager.init();Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);// ① 存入缓存userCache.put(1, "zzc");// ② 从缓存中取出String name = userCache.get(1);System.out.println(name);// ③ 删除缓存userCache.remove(1);System.out.println("删除成功");// ④ 再次获取缓存数据name = userCache.get(1);System.out.println(name);cacheManager.close();}
}
5.1.2.2、API 配置
5.1.2.2.1、新建一个配置类
public class EhCacheConfig {private CacheManager cacheManager;public EhCacheConfig() {this.cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("userCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class,String.class,ResourcePoolsBuilder.newResourcePoolsBuilder()// 最大条目数.heap(100).build()).build())// 初始化 CacheManager.build(true);}public Cache<Integer, String> getCache(String cacheName) {return cacheManager.getCache(cacheName, Integer.class, String.class);}public void close() {if (cacheManager != null) {cacheManager.close();}}
}
5.1.2.2.2、使用 EhCache
public class Test {public static void main(String[] args) {EhCacheConfig cacheConfig = new EhCacheConfig();Cache<Integer, String> userCache = cacheConfig.getCache("userCache");// ① 存入缓存userCache.put(1, "zzc");// ② 从缓存中取出String name = userCache.get(1);System.out.println(name);// ③ 删除缓存userCache.remove(1);System.out.println("删除成功");// ④ 再次获取缓存数据name = userCache.get(1);System.out.println(name);cacheConfig.close();}
}
5.1.2.2.3、EhCache 数据存储位置
EhCache3.x
版本中不但提供了堆内缓存 heap,还提供了堆外缓存 off-heap,并且还提供了数据的持久化操作,可以将数据落到磁盘中 disk
- heap:使用堆内内存
- heap(10):当前 Cache 最多只能存储 10 个数据,当你 put 第 11 个数据时,第一个数据就会被移除
- heap(10,大小单位MB):当前 Cache 最多只能存储 10MB 数据
- off-heap:堆外内存。将存储的数据放到操作系统的一块内存区域存储,不是JVM内部,这块空间属于RAM。这种对象是不能直接拿到JVM中使用的,在存储时,需要对数据进行序列化操作,同时获取出来的时候也要做反序列化操作
- disk:磁盘。将数据落到本地磁盘,这样的话,当服务重启后,依然会从磁盘反序列化数据到内存中
EhCache 提供了三种组合方式:
- heap + off-heap
- heap + disk
- heap + off-heap + disk
在组合情况下存储,存储数据时,数据先落到堆内内存,同时同步到对外内存以及本地磁盘。本地底盘因为空间充裕,所以本地磁盘数据是最全的。而且 EhCache 要求空间大小必须 disk > off-heap > heap
在组合情况下读取,因为性能原型,肯定是先找heap查询数据,没有数据去off-heap查询数据,off-heap没有数据再去disk中读取数据,同时读取数据之后,可以将数据一次同步到off-heap、heap
通过 API 实现组合存储方式:
public EhCacheConfig() {String path = "D:/temp";this.cacheManager = CacheManagerBuilder.newCacheManagerBuilder()// 设置disk存储的位置.with(CacheManagerBuilder.persistence(path)).withCache("userCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class,String.class,ResourcePoolsBuilder.newResourcePoolsBuilder()// 堆内存 最大条目数.heap(100)// 堆外内存.offheap(10, MemoryUnit.MB)// 磁盘 记得添加true,才能正常的持久化,并且序列化以及反序列化.disk(100, MemoryUnit.MB, true).build()).build())// 初始化 CacheManager.build(true);
}
本地磁盘存储的方式,一共有三个文件
- mata:元数据存储,记录这当前 cache 的 key 类型和 value 类型
- data:存储具体数据的位置,将数据序列化成字节存储
- index:类似索引,帮助查看数据的
5.1.2.2.4、数据生存时间
因为数据如果一致存放在内存当中,可能会出现内存泄漏等问题,数据在内存,一致不用,还占着空间
EhCache 对数据设置生存时间的机制提供了三种机制【三选一】:
- noExpiration:不设置生存时间
- timeToLiveExpiration:从数据落到缓存计算生存时间
- timeToIdleExpiration:从最后一个 get 计算生存时间
public EhCacheConfig() {String path = "D:/temp";this.cacheManager = CacheManagerBuilder.newCacheManagerBuilder()// 设置disk存储的位置.with(CacheManagerBuilder.persistence(path)).withCache("userCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class,String.class,ResourcePoolsBuilder.newResourcePoolsBuilder()// 堆内存 最大条目数.heap(100)// 堆外内存.offheap(10, MemoryUnit.MB)// 磁盘 记得添加true,才能正常的持久化,并且序列化以及反序列化.disk(100, MemoryUnit.MB, true).build())// 【三选一】不设置生存时间//.withExpiry(ExpiryPolicy.NO_EXPIRY)// 设置生存时间,从存储开始计算//.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMillis(1000)))// 设置生存时间,每次获取数据后,重置生存时间.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(1000))).build())// 初始化 CacheManager.build(true);
}
5.2、在 SpringBoot 中使用 Ehcache
5.2.1、引入依赖
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.9.3</version>
</dependency>
5.2.2、配置 Ehcache
5.2.2.1、XML 配置文件
5.2.2.1.1、新建一个配置文件
<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/schema/ehcache-core-3.0.xsd"><cache alias="userCache"><key-type>java.lang.Integer</key-type><value-type>java.lang.String</value-type><expiry><!-- 设置过期时间为 5 分钟 --><ttl unit="minutes">5</ttl></expiry><resources><!-- 最大条目数 --><heap unit="entries">100</heap></resources></cache>
</config>
5.2.2.1.2、启动类开启缓存注解
启动类上添加注解 @EnableCaching
5.2.2.1.3、添加配置类
@Configuration
public class EhCacheConfig {@Bean(name = "ehCacheManager")public CacheManager cacheManager() {XmlConfiguration xmlConfig = new XmlConfiguration(EhCacheConfig.class.getResource("/ehcache/ehcache.xml"));CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);// 确保初始化cacheManager.init();return cacheManager;}
}
5.2.2.1.4、使用 Ehcache
@RestController
public class TeController {@Autowiredprivate CacheManager cacheManager;@GetMapping("/test")public String test(Integer key) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);userCache.put(key, "Value for " + key);String value = userCache.get(key);System.out.println(value);userCache.remove(key);System.out.println("删除成功");value = userCache.get(key);System.out.println(value);return "Value for " + key;}
}
5.2.2.2、API 配置
5.2.2.2.1、新建一个配置类
@Configuration
public class EhCacheConfig {@Bean(name = "ehCacheManager")public CacheManager cacheManager() {String path = "D:/temp";return CacheManagerBuilder.newCacheManagerBuilder()// 设置disk存储的位置.with(CacheManagerBuilder.persistence(path)).withCache("userCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class,String.class,ResourcePoolsBuilder.newResourcePoolsBuilder()// 堆内存 最大条目数.heap(100)// 堆外内存.offheap(10, MemoryUnit.MB)// 磁盘 记得添加true,才能正常的持久化,并且序列化以及反序列化.disk(100, MemoryUnit.MB, true).build())// 设置生存时间,每次获取数据后,重置生存时间.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(1000))).build())// 初始化 CacheManager.build(true);}}
5.2.2.2.2、使用 Ehcache
@RestController
public class TeController {@Autowiredprivate CacheManager cacheManager;@GetMapping("/test")public String test(Integer key) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);userCache.put(key, "Value for " + key);String value = userCache.get(key);System.out.println(value);userCache.remove(key);System.out.println("删除成功");value = userCache.get(key);System.out.println(value);return "Value for " + key;}
}
5.3、集成 Spring Cache
5.3.1、引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.9.3</version>
</dependency>
5.3.2、启动类开启缓存注解
启动类上添加注解 @EnableCaching
5.3.3、配置 Ehcache
这里以 API 的方式进行配置,并将配置信息放入 yml 配置文件中
5.3.3.1、添加配置信息
yml 配置文件中添加如下信息:
# 准备EhCache基础配置项
ehcache:heap: 1000 # 堆内内存缓存个数off-heap: 10 # 对外内存存储大小 MBdisk: 20 # 磁盘存储数据大小 MBdiskDir: D:/data/ # 磁盘存储路径cacheNames: # 基于CacheManager构建多少个缓存- userCache- itemCache
5.3.3.2、配置属性类
@Data
@Component
@ConfigurationProperties(prefix = "ehcache")
public class EhCacheProperty {private int heap;private int offheap;private int disk;private String diskDir;private Set<String> cacheNames;
}
5.3.3.3、配置 CachaManager
@Configuration
public class EhCacheConfig {@Autowiredprivate EhCacheProperty ehCacheProperty;@Bean(name = "ehCacheManager")public CacheManager cacheManager() {// ①:设置内存存储位置和数量大小ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder()// 堆内存.heap(ehCacheProperty.getHeap())// 堆外内存.offheap(ehCacheProperty.getOffheap(), MemoryUnit.MB)// 磁盘.disk(ehCacheProperty.getDisk(),MemoryUnit.MB, true).build();// ②:设置生存时间ExpiryPolicy userExpiry = ExpiryPolicyBuilder.noExpiration();ExpiryPolicy itemExpiry = ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(1000));// ③:设置 CacheConfigurationCacheConfiguration userCache = CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, resourcePools).withExpiry(userExpiry).build();CacheConfiguration itemCache = CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, resourcePools).withExpiry(itemExpiry).build();// ④:设置磁盘存储的位置CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilder = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(ehCacheProperty.getDiskDir()));// ⑤:设置缓存名称Set<String> cacheNames = ehCacheProperty.getCacheNames();Map<String, CacheConfiguration> cacheMap = new HashMap<>(2);cacheMap.put("userCache", userCache);cacheMap.put("itemCache", itemCache);for (String cacheName : cacheNames) {cacheManagerBuilder = cacheManagerBuilder.withCache(cacheName, cacheMap.get(cacheName));}// 初始化 CacheManagerreturn cacheManagerBuilder.build(true);}}
5.3.4、使用 Ehcache
Spring Boot 提供了 @Cacheable
、@CachePut
、@CacheEvict
等注解来简化缓存操作,同时也支持基于缓存管理器的编程方式
5.3.4.1、基于注解的缓存
5.3.4.1.1、新建一个 UserServiceImpl
@Slf4j
@Service
@CacheConfig(cacheNames = "userCache")
public class UserServiceImpl {// 模拟数据库数据private Map<Integer, User> userMap = new HashMap<>();@CachePut(key = "#user.id")public User add(User user) {log.info("add");userMap.put(user.getId(), user);return user;}@Cacheable(key = "#id", unless = "#result == null")public User get(Integer id) {log.info("get");return userMap.get(id);}@CachePut(key = "#user.id")public User update(User user) {log.info("update");userMap.put(user.getId(), user);return user;}@CacheEvict(key = "#id")public void delete(Integer id) {log.info("delete");userMap.remove(id);}}
5.3.4.1.2、新建一个 TestController
@RestController
public class TeController {@Autowiredprivate UserServiceImpl userServiceImpl;@PostMappingpublic String add(@RequestBody User user) {userServiceImpl.add(user);return "add";}@GetMapping("/{id}")public User get(@PathVariable Integer id) {User user = userServiceImpl.get(id);return user;}@PutMappingpublic String update(@RequestBody User user) {userServiceImpl.update(user);return "update";}@DeleteMapping("/{id}")public String delete(@PathVariable Integer id) {userServiceImpl.delete(id);return "delete";}}
5.3.4.12、基于缓存管理器的编程方式
Spring Boot 中,可以使用 CacheManager
和 Cache
接口来实现缓存的管理和操作
@RestController
public class TeController {@Autowiredprivate CacheManager cacheManager;@PostMappingpublic String add(@RequestBody User user) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);if (Objects.nonNull(userCache)) {userCache.put(user.getId(), JSON.toJSONString(user));}return "add";}@GetMapping("/{id}")public User get(@PathVariable Integer id) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);if (Objects.nonNull(userCache)) {String s = userCache.get(id);return JSON.parseObject(s, User.class);}return null;}@PutMappingpublic String update(@RequestBody User user) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);if (Objects.nonNull(userCache)) {userCache.put(user.getId(), JSON.toJSONString(user));}return "update";}@DeleteMapping("/{id}")public String delete(@PathVariable Integer id) {Cache<Integer, String> userCache = cacheManager.getCache("userCache", Integer.class, String.class);if (Objects.nonNull(userCache)) {userCache.remove(id);}return "delete";}
}