SpringBoot 集成 Ehcache 实现本地缓存

news2024/11/26 19:14:27

目录

  • 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 会首先检查该数据是否已经存在于缓存中。如果数据已经存在于缓存中,则更新该数据;否则,将该数据写入缓存。如下:

  1. 当应用程序请求写入一个数据项到 Ehcache 中时,这个数据项被传递给Ehcache API
  2. Ehcache 首先根据该数据项的键值对定位其对应的 Cache 对象
  3. Ehcache 根据配置中的缓存策略,比如是否应该在缓存中创建一个新的元素,以及新元素是否会淘汰老的元素
  4. 如果需要创建一个新缓存元素,则 Ehcache 创建一个新的元素并将其添加到 Cache 对象中
  5. 如果缓存中已经存在该元素,Ehcache 会根据缓存策略对该元素进行更新或替换
  6. Ehcache 将更新后的 Cache 对象返回给应用程序

3.2、缓存查找

当应用程序需要查询缓存中的数据时,Ehcache 首先会检查该数据是否存在于缓存中。如果数据存在于缓存中,则直接返回缓存数据;否则,从数据库或其他资源获取数据,并将其存入缓存中。如下:Ehcache 缓存查找的详细流程。

  1. 当应用程序请求从 Ehcache 中读取一个数据项时,这个请求被传递给 Ehcache API。
  2. Ehcache 首先根据该数据项的键值对定位其对应的 Cache 对象。
  3. Ehcache 检查该数据项是否已经存在于缓存中。
  4. 如果数据项存在于缓存中,Ehcache 可以直接将其返回给应用程序。
  5. 如果数据项不存在于缓存中,Ehcache 就需要从数据库或其他数据源(如文件、网络等)中获取数据。
  6. 获取到数据后,Ehcache 会将其添加到缓存中并返回给应用程序

3.3、缓存过期和驱逐

Ehcache 提供了多种缓存失效策略,例如基于时间的缓存失效、基于访问的缓存失效、基于大小的缓存失效等。当缓存数据过期或缓存空间不足时,Ehcache 会选择一部分缓存元素进行驱逐以腾出更多的内存空间。如下:

  1. Ehcache 会周期性地扫描缓存中的元素来标记那些已经过期的元素。
  2. Ehcache根据缓存策略(如基于时间、基于访问、基于大小等)判断哪些缓存元素应该被驱逐。
  3. 驱逐过程通常是异步执行的,Ehcache 会在后台线程上执行这个操作

3.4、缓存持久化

Ehcache 还提供了缓存持久化功能,它可以将缓存中的数据持久化到磁盘或者其他数据源。在应用程序重启或者缓存失效后,Ehcache 可以从持久化存储中恢复数据,从而保证数据的完整性和可靠性。如下:

  1. Ehcache 使用磁盘存储或数据库等持久化技术来存储缓存数据。
  2. 当缓存中的数据更新时,Ehcache 会自动将此数据持久化到持久化存储中。
  3. 在应用程序重启或者缓存失效后,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 找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <defaultCache
            maxEntriesLocalHeap="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:是否缓存虚拟机重启期数据,默认为 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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳
                                  离当前时间最远的元素将被清出缓存。
    -->
    <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();
    }
}

可以使用 putgetremove 等方法进行缓存操作

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);
        // 初始化 CacheManager
        cacheManager = 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 {

    @Autowired
    private 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 {

    @Autowired
    private 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         # 对外内存存储大小 MB
  disk: 20             # 磁盘存储数据大小  MB
  diskDir: 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 {

    @Autowired
    private 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));
        // ③:设置 CacheConfiguration
        CacheConfiguration 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));
        }
        // 初始化 CacheManager
        return 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 {
    @Autowired
    private UserServiceImpl userServiceImpl;

    @PostMapping
    public 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;
    }

    @PutMapping
    public 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 中,可以使用 CacheManagerCache 接口来实现缓存的管理和操作

@RestController
public class TeController {

    @Autowired
    private CacheManager cacheManager;

    @PostMapping
    public 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;
    }

    @PutMapping
    public 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";
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2194106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字节放大招:无需LORA训练,小红书写真轻松搞定,Pulid-Flux换脸方案来了

前言 在这之前&#xff0c;SD常用的换脸节点还不支持Flux模型&#xff0c;使用Flux 做虚拟模特最好的方法是炼制人脸lora&#xff0c;但是炼丹是个有技术门槛的活。 之前文章有提过字节跳动的 Pulid团队&#xff0c;率先推出了Pulid-Flux模型&#xff0c;但是之前只能在线上使用…

vivo/iqoo原子笔记 拍试卷去手写或者叫还原试卷。

1、如果我们经常做试卷的时候&#xff0c;发现有错的&#xff0c;想重新做一下。那就要去掉原来的手写的答案。 2、网上的App或软件多的就是&#xff0c;但大多是要收费的&#xff0c;那么我们如何利用手机里的功能&#xff0c;来基本达到这一效果呢&#xff1f; 3、手机自动…

Spring Boot实现的医院资源优化工具

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

ASCII码、Unicode编码和UTF-8编码介绍

1.ASCII码 2.Unicode编码 3.UTF-8编码

如何训练自己的大模型,答案就在这里。

训练自己的AI大模型是一个复杂且资源密集型的任务&#xff0c;涉及多个详细步骤、数据集需求以及计算资源要求。以下是根据搜索结果提供的概述&#xff1a; 详细步骤 \1. 设定目标&#xff1a; - 首先需要明确模型的应用场景和目标&#xff0c;比如是进行分类、回归、生成文本…

实现一个计算器的功能(一般形式、函数指针数组的形式、回调函数的形式)

实现一个计算器的功能&#xff1a; 一般的形式&#xff1a; #include<stdio.h> int Add(int x, int y) {return x y; } int Sub(int x, int y) {return x - y; } int Mul(int x, int y) {return x * y; } int Div(int x, int y) {return x / y; } void menu() {printf…

【Linux】Linux命令与操作详解(一)文件管理(文件命令)、用户与用户组管理(创建、删除用户/组)

文章目录 一、前言1.1、Linux的文件结构是一颗从 根目录/ 开始的一个多叉树。1.2、绝对路径与相对路径1.3、命令的本质是可执行文件。1.4、家目录 二、文件管理2.1、文件操作1、pwd2、ls3、cd4、touch5、mkdir6、cp7、rm8、mv9、rmdir 2.2、查看文件1、cat2、more3、less4、hea…

6.1K Star,简简单单的看直播

Hi&#xff0c;骚年&#xff0c;我是大 G&#xff0c;公众号「GitHub 指北」会推荐 GitHub 上有趣有用的项目&#xff0c;一分钟 get 一个优秀的开源项目&#xff0c;挖掘开源的价值&#xff0c;欢迎关注。 导语 在视频内容飞速发展的时代&#xff0c;实时推流和流媒体技术成…

java并发之并发实践

一、死锁 线程死锁 死锁是指两个或者两个以上的线程在执行的过程中&#xff0c;因争夺资源产生的一种互相等待现象。 假设线程 A 持有资源 1&#xff0c;线程 B 持有资源 2&#xff0c;它们同时都想申请对方的资源&#xff0c;那么这两个线程就会互相等待而进入死锁状态。 使用…

多功能声学综合馆:流动会场的新标杆—轻空间

随着现代会议、展览、演出和活动的多元化需求&#xff0c;场地的灵活性与适应性变得尤为重要。传统的固定场馆难以满足各类活动的复杂需求&#xff0c;而多功能声学综合馆凭借其灵活、便捷、专业的声学性能&#xff0c;成为了市场上一颗闪耀的新星。其“流动会场”的特性&#…

计算机取证

文章目录 思维导图计算机取证数据固定FTK ImageDumpIt 数据分析——磁盘镜像仿真软件自动仿真手动仿真仿真后的取证分析 基本信息及用户痕迹1.名称、版本、build号、系统目录、位数、产品秘钥等2.安装时间3.最后一次关机时间4.USB使用记录5.WIFI信息6.近期访问过的文档、程序7.…

动销方案:剑指市场份额扩张

在竞争激烈的市场中&#xff0c;企业如何扩大市场份额&#xff1f;动销&#xff0c;即拉动销售&#xff0c;乃是关键手段。 首先进行市场分析。行业现状方面&#xff0c;以快速消费品行业为例&#xff0c;市场规模大且持续增长&#xff0c;但竞争激烈&#xff0c;各大品牌不断推…

深化理解:RAG应用搭建进阶指南

大型语言模型&#xff08;LLM&#xff09;的文本推理能力&#xff0c;宛如一位博学的公民&#xff0c;其智慧之源来自于互联网上公开的文献宝库。想象一下&#xff0c;这位名为LLM的公民&#xff0c;如同一位勤奋的学者&#xff0c;借阅了图书馆中所有的书籍&#xff0c;并将这…

杀疯了深度解析chatGPT和NLP底层技术——复旦大学新版《自然语言处理导论》

在今年的2月28号&#xff0c;复旦张琦教授放出了自己的大招&#xff0c;发布了自己历时近三年之久&#xff0c;即自身对自然语言处理20年研究的著作 全文共 600页&#xff0c; 涉及了 787 篇参考文献&#xff0c; 全面且深度的解析了与NLP的底层知识。 内容介绍&#xff1a; …

【C++ Primer Plus】4

2 字符串 字符串是存储在内存的连续字节中的一系列字符&#xff1b;C处理字符串的方式有两种&#xff0c; c-风格字符串&#xff08;C-Style string&#xff09;string 类 2.1 c-风格字符串&#xff08;C-Style string&#xff09; 2.1.1 char数组存储字符串&#xff08;c-…

网 络 安 全

网络安全是指保护网络系统及其所存储或传输的数据免遭未经授权访问、使用、揭露、破坏、修改或破坏的实践和技术措施。网络安全涉及多个方面&#xff0c;包括但不限于以下几个方面&#xff1a; 1. 数据保护&#xff1a;确保数据在传输和存储过程中的完整性和保密性&#xff0c;…

微服务es+Kibana解析部署使用全流程

1、介绍 ElasticSearch是Java开发的一款开源的&#xff0c;分布式的搜索引擎。 它的搜索采用内存中检索的方式&#xff0c;大大提高了检索的效率&#xff0c;es是基于REST API的方式对数据操作的&#xff0c;可以让存储、检索、索引效率更高。 1、es可以做什么 网站检索数据…

python爬虫 - 深入requests模块

&#x1f308;个人主页&#xff1a;https://blog.csdn.net/2401_86688088?typeblog &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html 目录 ​编辑 前言 一、下载网络文件 &#xff08;一&#xff09;基本步骤 &#xff0…

【AIGC】如何选择AI绘画工具?Midjourney VS Stable Diffusion

前言 文章目录 &#x1f4af;如何选择合适的AI绘画工具 个人需求选择比较工具特点社区和资源 &#x1f4af; Midjourney VS Stable Diffusion&#xff1a;深度对比与剖析 使用费用对比使用便捷性与系统兼容性对比开源与闭源对比图片质量对比上手难易对比学习资源对比作品版权问…

Vue入门-指令学习-v-else和v-else-if

v-else和v-else-if 作用&#xff1a;辅助v-if进行判断渲染 语法&#xff1a;v-else v-else-if"表达式" 注意&#xff1a;需要紧挨着v-if一起使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><m…