SpringBoot 集成 Ehcache 实现本地缓存
目录
- 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";}
}
相关文章:

SpringBoot 集成 Ehcache 实现本地缓存
目录 1、Ehcache 简介2、Ehcache 集群方式3、工作原理3.1、缓存写入3.2、缓存查找3.3、缓存过期和驱逐3.4、缓存持久化 4、入门案例 —— Ehcache 2.x 版本4.1、单独使用 Ehcache4.1.1、引入依赖4.1.2、配置 Ehcache4.1.2.1、XML 配置方式4.1.2.1.1、新建 ehcache.xml4.1.2.1.2…...

CSP-J 复赛真题 P9749 [CSP-J 2023] 公路
文章目录 前言[CSP-J 2023] 公路题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 示例代码代码解析思考过程总结 总结 前言 在CSP-J 2023的复赛中,出现了一道引人注目的题目——“公路”。这道题目不仅考察了选手们对算法的理解和运用能力,…...

MeterSphere压测配置说明
在MeterSphere中,执行性能测试时的配置参数对测试结果有重要影响。以下是对MeterSphere压测配置中几个关键参数的解释: 执行方式:决定了测试的执行模式,例如可以按照持续时间或迭代次数来执行测试。 按持续时间:在这种…...

数据库软题6.1-关系模式-关系模式的各种键
关系模式的各种键 题1-由关系模式求候选键 1. 候选键唯一不冗余 对选项进行闭包运算,如果得到全部属性U,则为候选码 A:AC-ABC-ABCD B:AB-ABC-ABCD C:AE-ABE-ABCE -ABCDE-ABCDEH D:DE2. R的候选码可以从A1,A2,A3,A1A2,A1A3,A2A3,A1A2A3中选择ÿ…...

ulimit:资源限制
一、命令简介 ulimit 是一个用于资源管理的工具,对于确保系统资源的合理分配和安全使用至关重要。 使用场景: 系统管理:限制用户进程使用的资源,防止资源滥用,保证系统稳定。调试:调整核心文件大…...

解决Python使用Selenium 时遇到网页 <body> 划不动的问题
如果在使用 Selenium 时遇到网页的 <body> 划不动的问题,这通常是因为页面的滚动机制(例如,可能使用了一个具有固定高度的容器或自定义的滚动条)导致无法通过简单的 JavaScript 实现滚动。可以通过以下方法来解决该问题。 …...

pytorch版本和cuda版本不匹配问题
文章目录 🌕问题:Python11.8安装pytorch11.3失败🌕CUDA版本和pytorch版本的关系🌕安装Pytorch2.0.0🌙pip方法🌙cuda方法 🌕问题:Python11.8安装pytorch11.3失败 🌕CUDA版…...

Vue/组件的生命周期
这篇文章借鉴了coderwhy大佬的Vue生命周期 在Vue实例化或者创建组件的过程中 内部涉及到一系列复杂的阶段 每一个阶段的前后时机都可能对应一个钩子函数 以下是我根据coderwhy大佬文章对于每一个阶段的一些看法 1.过程一 首先实例化Vue或者组件 在实例化之前 会对应一个钩子函…...

【Nacos架构 原理】内核设计之Nacos寻址机制
文章目录 前提设计内部实现单机寻址文件寻址地址服务器寻址 前提 对于集群模式,集群内的每个Nacos成员都需要相互通信。因此这就带来一个问题,该以何种方式去管理集群内部的Nacos成员节点信息,即Nacos内部的寻址机制。 设计 要能够感知到节…...

入门案例:mybatis流程,核心,常见错误
入门案例:mybatis执行流程分析 说明: 1.第一步:是从核心配置文件mybatis-config.xml中构建SqlSessionFactory对象,由于核心配置文件mybatis-config.xml中关联了映射文件UserMapper.xml,所以在SqlSessionFactory中也存在映射文件的…...

C++ | Leetcode C++题解之第456题132模式
题目: 题解: class Solution { public:bool find132pattern(vector<int>& nums) {int n nums.size();vector<int> candidate_i {nums[0]};vector<int> candidate_j {nums[0]};for (int k 1; k < n; k) {auto it_i upper_…...

自然语言处理问答系统
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

Python的几个高级特性
引言 Python是一种功能强大的编程语言,它简洁的语法和强大的库支持使其成为数据科学和机器学习领域的热门选择。在Python的高级特性中,生成器、迭代器、闭包、装饰器和内置高阶函数是实现高效、优雅代码的关键。本文将逐一介绍这些特性,并提…...

【颜色平衡树 / E】
题目 思路 DFS暴力 60分 代码 #include <bits/stdc.h> using namespace std; const int N 5010; const int M 5010; int h[N], e[M], ne[M], idx; int c[N], f; int ans; void add(int a, int b) // 添加一条边a->b {e[idx] b, ne[idx] h[a], h[a] idx ; } …...

滑动窗口--(中篇)
将X减到0的最小操作数 给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。 如果可以将 x 恰好 减到 0 ,返…...

Java性能调优:实战技巧与最佳实践
引言 Java作为企业级应用开发的首选语言之一,其性能直接影响到系统的响应速度和用户体验。性能调优是一项复杂的工作,涉及多个层面的知识和技术。本文将通过具体的示例,探讨一些常见的性能调优技巧及最佳实践。 1. 了解你的应用程序 示例&…...

排版套料系统设计说明
先上效果图 项目地址 1.产品介绍 产品名称:StreamFit 智能排版套料系统 主要功能: 智能排版优化 功能描述:StreamFit 利用先进的算法技术,自动对各类材料(如布料、金属板材、纸张等)进行高效排版布局&am…...

算法修炼之路之二分查找
目录 一:三大二分介绍及模板 1.普通二分 2.查找左右边界的二分及模板 二:LeetCode OJ练习 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 一:三大二分介绍及模板 1.普通二分 这里通过一道题来引出普通二分及模板 LeetCode_704 二分查找 画图分析: 具体代…...

OpenAI预计明年将推出“代理”系统
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

每日OJ题_牛客_重排字符串_贪心_C++_Java
目录 牛客_重排字符串_贪心 题目解析 C代码 Java代码 牛客_重排字符串_贪心 重排字符串 (nowcoder.com) 描述: 小红拿到了一个只由小写字母组成的字符串。她准备把这个字符串重排(只改变字母的顺序,不改变数量) …...

Python 进阶部分详细整理
1. 面向对象编程(OOP) 面向对象编程 (OOP) 是一种通过将程序中的数据和功能封装为对象的编程范式。OOP 基于四个核心概念:类与对象、继承、封装与多态。 类与对象 类(Class):类是创建对象的蓝图或模板。它…...

[ RK3566-Android11 ] 关于移植 RK628F 驱动以及后HDMI-IN图像延迟/无声等问题
问题描述 由前一篇文章https://blog.csdn.net/jay547063443/article/details/142059700?fromshareblogdetail&sharetypeblogdetail&sharerId142059700&sharereferPC&sharesourcejay547063443&sharefromfrom_link,移植HDMI-IN部分驱动后出现&a…...

【黑马点评】 使用RabbitMQ实现消息队列——2.使用RabbitMQ监听秒杀下单
2 使用RabbitMQ实现消息队列 2.1 修改\hm-dianping\pom.xmlpom.xml文件 添加RabbitMQ的环境 <!-- RabbitMQ--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </depe…...

业务封装与映射 -- OTUk/ODUk/OPUk开销帧结构
开销是为了保证净荷正常、灵活传送所必须附加的供网络运行、管理和维护(OAM)使用的字节。 OTN电层开销包括OTUk开销、ODUk开销、OPUk开销、OTUCn开销、ODUCn开销、OPUCn开销和帧对齐开销。 SM开销属于OTU开销,占用3个字节;PM开销…...

Vim基本用法
Vim用法 一、基本模式 1. 普通模式(Normal Mode) 移动光标 基本移动:使用方向键(h左移、j下移、k上移、l右移),也可以使用 H(移到屏幕顶部)、M(移到屏幕中间ÿ…...

python 实现Tarjan 用于在有向图中查找强连通分量的算法
Tarjan 用于在有向图中查找强连通分量的算法介绍 Tarjan算法是一种用于在有向图中查找强连通分量的高效算法,由Robert Tarjan在1972年提出。强连通分量是指在有向图中,如果从顶点u到顶点v以及从顶点v到顶点u都存在一条路径,那么顶点u和顶点v…...

Qt开发技巧(十五)字符串去除空格,跨网段搜索不生效,设置图片显示失败问题,表格视图的批量删除,主动判断字串编码,开启向前查询的属性,画家类载入html来绘制
继续讲一些Qt开发中的技巧操作: 1.字符串去除空格 我们经常会遇到字符串重去除空格的情况,对于QString去除空格,有多种场景,可能需要去除左侧、右侧、所有等位置的空格; //字符串去空格 -1移除左侧空格 0移除所有空格…...

【机器学习】智驭未来:探索机器学习在食品生产中的革新之路
📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀目录 🔍1. 引言:探索机器学习在食品生产中的革新之路📒2. 机器学习在食品质量控制中的应用🌞实…...

Ubuntu 安装CUDA并使用Docker配置Pytorch环境
文章目录 参考安装顺序Nvidia GPU driverDockerNvidia Container ToolkitDocker PyTorch 1. Nvidia GPU Driver2. Docker 安装(使用apt存储库进行安装)3. Nvidia Container Toolkit3.1 Docker测试GPU 参考 安装顺序 Nvidia GPU driver Docker Nvidia…...

【论文阅读】Simulating 500 million years of evolution with a language model
Simulating 500 million years of evolution with a language model 1、概述 展示了语言模型在蛋白质设计和进化模拟方面的能力。通过对 ESM3 模型的研究,发现其能够生成与自然蛋白质差异较大且具有功能的新蛋白质,如新型绿色荧光蛋白(GFP),表明语言模型可以达到自然进化…...