[Java实战]Spring Boot 3 整合 Ehcache 3(十九)

news2025/5/16 4:20:05

[Java实战]Spring Boot 3 整合 Ehcache 3(十九)

引言

在微服务和高并发场景下,缓存是提升系统性能的关键技术之一。Ehcache 作为 Java 生态中成熟的内存缓存框架,其 3.x 版本在性能、功能和易用性上均有显著提升。本文将详细介绍如何在 Spring Boot 3 中整合 Ehcache 3,并实现高效缓存管理。

一. 环境准备

  • open JDK 17+:Spring Boot 3 要求 Java 17 及以上。
  • Spring Boot 3.4.5:使用最新稳定版。
  • Ehcache 3.10+:支持 JSR-107 标准,兼容 Spring Cache 抽象。
  • 构建工具:Maven 或 Gradle(本文以 Maven 为例)。

二. 添加依赖

pom.xml 中添加 Ehcache 3 和 Spring Cache 依赖:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring Cache 抽象 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
    <!-- Ehcache 3.x 核心库 -->
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.10.0</version>
        <classifier>jakarta</classifier> <!-- 针对高版本 JDK,添加 Jakarta 分类器 -->
    </dependency>
    

三. 配置 Ehcache 3

3.1 启用缓存

在 Spring Boot 主类或配置类上添加 @EnableCaching 注解:

@SpringBootApplication
@EnableCaching
@MapperScan("com.example.springboot3.mapper")
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

3.2 创建 Ehcache 配置文件

resources 目录下新建 ehcache.xml,定义缓存策略:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.ehcache.org/v3"
        xmlns:jsr107="http://www.ehcache.org/v3/jsr107">
    <service>
        <jsr107:defaults enable-management="true" enable-statistics="true"/>
    </service>
    <cache alias="productCache">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.Object</value-type>
        <expiry>
            <ttl unit="seconds">120</ttl>
        </expiry>
        <resources>
            <heap unit="entries">1000</heap>
            <offheap unit="MB">10</offheap>
        </resources>
    </cache>
</config>

3.3 配置 Spring Boot 使用 Ehcache

application.yml 中指定 Ehcache 配置文件路径:

spring:
  cache:
    jcache:
      config: classpath:ehcache.xml
    type: jcache

四. 实现缓存逻辑

4.1 定义服务类

使用 @Cacheable@CachePut@CacheEvict 注解管理缓存:

/**
 * ProductService - 类功能描述
 *
 * @author csdn:曼岛_
 * @version 1.0
 * @date 2025/5/12 15:01
 * @since JDK 17
 */
@Service
public class ProductService {

    @Autowired
    private ProductMapper productMapper;

    //从数据库查询并缓存结果
    @Cacheable(cacheNames = "productCache",key = "#id.toString()")
    public Product getProductById(Long id) {

        return productMapper.selectById(id);
    }

   //更新产品信息并更新缓存
    @CachePut(cacheNames = "productCache",key = "#product.id.toString()")
    public void updateProduct(Product product) {
        productMapper.updateById(product);
    }

    //更新或删除时清除缓存
    @CacheEvict(cacheNames = "productCache", key = "#id.toString()", allEntries = false)
    public void deleteProduct(Long id) {
        productMapper.deleteById(id);
    }
}

五. 高级配置与优化

5.1 自定义 CacheManager

通过 JCacheManagerCustomizer 配置多级缓存或动态缓存:


/**
 * EhcacheConfig - 类功能描述
 *
 * @author csdn:曼岛_
 * @version 1.0
 * @date 2025/5/13 14:21
 * @since JDK 17
 */
@Configuration
public class EhcacheConfig {

    @Bean
    public JCacheManagerCustomizer cacheManagerCustomizer() {
        return cm -> {
            CachingProvider provider = Caching.getCachingProvider();
            CacheManager cacheManager = null;
            try {
                cacheManager = provider.getCacheManager(
                        getClass().getResource("/ehcache.xml").toURI(),
                        getClass().getClassLoader()
                );
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }

        };
    }
}

5.2 监控与统计

启用 Ehcache 统计信息:

spring:
  cache:
    jcache:
      provider: org.ehcache.jsr107.EhcacheCachingProvider

在代码中获取统计信息:

Cache<Long, Product> cache = cacheManager.getCache("productCache", Long.class, Product.class);
Eh107Cache<Long, Product> eh107Cache = (Eh107Cache<Long, Product>) cache;
Ehcache<Long, Product> ehcache = eh107Cache.getEhcache();
Statistics statistics = ehcache.getRuntimeConfiguration().getStatistics();

六. 测试验证

6.1 编写单元测试

使用 @SpringBootTest 测试缓存行为:

@SpringBootTest
public class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private CacheManager cacheManager;

    @Test
    public void testGetProductById() {
        // 清空缓存
        Cache cache = cacheManager.getCache("productCache");
        cache.clear();

        // 创建一个测试产品
        Product product = new Product();
        product.setName("Product");
        product.setPrice(100);
        product.setStock(1);
        productMapper.insert(product);

        // 第一次调用,应该从数据库获取数据
        Product result1 = productService.getProductById(product.getId());
        assertNotNull(result1);
        assertEquals(product.getName(), result1.getName());

        // 第二次调用,应该从缓存获取数据
        Product result2 = productService.getProductById(product.getId());
        assertNotNull(result2);
        assertEquals(product.getName(), result2.getName());

        // 验证缓存中存在该数据
        Cache.ValueWrapper valueWrapper = cache.get(product.getId().toString());
        assertNotNull(valueWrapper);
        assertEquals(product.getName(), ((Product) valueWrapper.get()).getName());
        
         // 打印缓存结果
        System.out.println("Cached Product: " + valueWrapper.get());
    }

    @Test
    public void testUpdateProduct() {
        // 清空缓存
        Cache cache = cacheManager.getCache("productCache");
        cache.clear();

        // 创建一个测试产品
        Product product = new Product();
        product.setName("Product");
        product.setPrice(100);
        product.setStock(2);
        productMapper.insert(product);

        // 更新产品信息
        product.setName("Updated Product");
        product.setPrice(200);
        productService.updateProduct(product);

        // 验证数据库中的数据是否更新
        Product updatedProduct = productMapper.selectById(product.getId().toString());
        assertEquals("Updated Product", updatedProduct.getName());
        assertEquals(200, updatedProduct.getPrice());

        // 验证缓存中的数据是否更新
        Cache.ValueWrapper valueWrapper = cache.get(product.getId().toString());
        assertNotNull(valueWrapper);
        assertEquals("Updated Product", ((Product) valueWrapper.get()).getName());
    }

    @Test
    public void testDeleteProduct() {
        // 清空缓存
        Cache cache = cacheManager.getCache("productCache");
        cache.clear();

        // 创建一个测试产品
        Product product = new Product();
        product.setName("Test Product");
        product.setPrice(100);
        product.setStock(1);
        productMapper.insert(product);

        // 将产品信息放入缓存
        productService.getProductById(product.getId());

        // 删除产品
        productService.deleteProduct(product.getId());

        // 验证数据库中的数据是否删除
        assertNull(productMapper.selectById(product.getId()));

        // 验证缓存中的数据是否删除
        assertNull(cache.get(product.getId().toString()));
    }
}

在这里插入图片描述

接口测试:

在这里插入图片描述

6.2 查看缓存状态

通过 Actuator 或日志观察缓存命中率(需添加 Actuator 依赖):

management:
  endpoints:
    web:
      exposure:
        include: cache

七. 常见问题与解决方案

7.1 缓存不生效

  • 检查点:确保 @EnableCaching 已启用,方法为 public,且调用来自 Spring 代理对象。
  • 日志调试:设置 logging.level.org.springframework.cache=DEBUG

7.2 序列化异常

  • 原因:缓存对象未实现 Serializable
  • 解决:为缓存对象添加 implements Serializable 或配置序列化策略。

7.3 依赖冲突

  • 排查工具:使用 mvn dependency:tree 检查版本一致性。
  • 推荐:使用 Spring Boot 管理的 Ehcache 版本。

八. 性能对比与选型建议

  • Ehcache vs Caffeine:Ehcache 支持多级缓存和持久化,适合复杂场景;Caffeine 更轻量,适合纯内存缓存。
  • Ehcache vs Redis:Ehcache 适用于单机内存缓存,Redis 适合分布式缓存。

结语

通过本文,您已掌握在 Spring Boot 3 中整合 Ehcache 3 的核心步骤与优化技巧。合理利用缓存机制,可以显著提升系统性能。建议根据业务场景选择合适的缓存策略,并通过监控持续优化。

扩展阅读:Ehcache 官方文档

希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!

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

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

相关文章

建筑物渗水漏水痕迹发霉潮湿分割数据集labelme格式1357张1类别

数据集中有增强图片详情看图片 数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1357 标注数量(json文件个数)&#xff1a;1357 标注类别数&#xff1a;1 标注类别名称:["water&qu…

第二十二天打卡

数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…

解锁性能密码:Linux 环境下 Oracle 大页配置全攻略​

在 Oracle 数据库运行过程中&#xff0c;内存管理是影响其性能的关键因素之一。大页内存&#xff08;Large Pages&#xff09;作为一种优化内存使用的技术&#xff0c;能够显著提升 Oracle 数据库的运行效率。本文将深入介绍大页内存的相关概念&#xff0c;并详细阐述 Oracle 在…

Spark,在shell中运行RDD程序

在hdfs中/wcinput中创建一个文件&#xff1a;word2.txt在里面写几个单词 启动hdfs集群 [roothadoop100 ~]# myhadoop start [roothadoop100 ~]# cd /opt/module/spark-yarn/bin [roothadoop100 ~]# ./spark-shell 写个11测试一下 按住ctrlD退出 进入环境&#xff1a;spa…

SAP学习笔记 - 开发11 - RAP(RESTful Application Programming)简介

上一章学习了BTP架构图&#xff0c;实操创建Directory/Subaccount&#xff0c;BTP的内部组成&#xff0c;BTP Cockpit。 SAP学习笔记 - 开发10 - BTP架构图&#xff0c;实操创建Directory/Subaccount&#xff0c;BTP的内部组成&#xff0c;BTP Cockpit-CSDN博客 本章继续学习S…

数据防泄密安全:企业稳健发展的守护盾

在数字化时代&#xff0c;数据已成为企业最核心的资产之一。无论是客户信息、财务数据&#xff0c;还是商业机密&#xff0c;一旦泄露&#xff0c;都可能给企业带来不可估量的损失。近年来&#xff0c;数据泄露事件频发&#xff0c;如Facebook用户数据泄露、Equifax信用数据外泄…

MySQL之基础索引

目录 引言 1、创建索引 2、索引的原理 2、索引的类型 3、索引的使用 1.添加索引 2.删除索引 3.删除主键索引 4.修改索引 5.查询索引 引言 当一个数据库里面的数据特别多&#xff0c;比如800万&#xff0c;光是创建插入数据就要十几分钟&#xff0c;我们查询一条信息也…

拉丁方分析

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著傅珏生译)第4章随机化区组&#xff0c;拉丁方&#xff0c;以及有关的设计第4.2节的python解决方案。本文尽量避免重复书中的理论&#xff0c;着于提供python解决方案&#xff0c;并与原书的运算结果进行对比。您…

软考软件设计师中级——软件工程笔记

1.软件过程 1.1能力成熟度模型&#xff08;CMM&#xff09; 软件能力成熟度模型&#xff08;CMM&#xff09;将软件过程改进分为以下五个成熟度级别&#xff0c;每个级别都定义了特定的过程特征和目标&#xff1a; 初始级 (Initial)&#xff1a; 软件开发过程杂乱无章&#xf…

5.5.1 WPF中的动画2-基于路径的动画

何为动画?一般只会动。但所谓会动,还不仅包括位置移动,还包括角度旋转,颜色变化,透明度增减。动画本质上是一个时间段内某个属性值(位置、颜色等)的变化。因为属性有很多数据类型,它们变化也需要多种动画类比如: BooleanAnimationBase\ ByteAnimationBase\DoubleAnima…

Andorid之TabLayout+ViewPager

文章目录 前言一、效果图二、使用步骤1.主xml布局2.activity代码3.MyTaskFragment代码4.MyTaskFragment的xml布局5.Adapter代码6.item布局 总结 前言 TabLayoutViewPager功能需求已经是常见功能了&#xff0c;我就不多解释了&#xff0c;需要的自取。 一、效果图 二、使用步骤…

26考研——中央处理器_指令流水线_流水线的冒险与处理 流水线的性能指标 高级流水线技术(5)

408答疑 文章目录 六、指令流水线流水线的冒险与处理结构冒险数据冒险延迟执行相关指令采用转发&#xff08;旁路&#xff09;技术load-use 数据冒险的处理 控制冒险 流水线的性能指标流水线的吞吐率流水线的加速比 高级流水线技术超标量流水线技术超长指令字技术超流水线技术 …

酒店旅游类数据采集API接口之携程数据获取地方美食品列表 获取地方美餐馆列表 景点评论

携程 API 接入指南 API 地址&#xff1a; 调用示例&#xff1a; 美食列表 景点列表 景点详情 酒店详情 参数说明 通用参数说明 请谨慎传递参数&#xff0c;避免不必要的费用扣除。 URL 说明&#xff1a;https://api-gw.cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京…

Lora原理及实现浅析

Lora 什么是Lora Lora的原始论文为《LoRA: Low-Rank Adaptation of Large Language Models》&#xff0c;翻译为中文为“大语言模型的低秩自适应”。最初是为了解决大型语言模在进行任务特定微调时消耗大量资源的问题&#xff1b;随后也用在了Diffusion等领域&#xff0c;用于…

【设计模式】- 创建者模式

单例模型 饿汉式 静态方法创建对象 public class Singleton {// 私有构造方法private Singleton(){}private static Singleton instance new Singleton();// 提供一个外界获取的方法public static Singleton getInstance(){return instance;} }静态代码块创建对象 public …

南审计院考研分享会 经验总结

汪学长 – 中科大 计科专硕 初试准备 数学先做真题&#xff0c;模拟题刷的越多分越高&#xff1b;408真题最重要&#xff0c;模拟题辅助&#xff1b;英语只做真题&#xff1b;政治9月份开始背 代码能力在低年级培养的重要性和路径 考研不选择机构原因 因为机构里面学习的框…

牛客练习赛138(首篇万字题解???)

赛时成绩如下&#xff1a; 1. 小s的签到题 小s拿到了一个比赛榜单&#xff0c;他要用最快的速度找到签到题&#xff0c;但是小s脑子还是有点晕&#xff0c;请你帮帮小s&#xff0c;助力他找到签到题。 比赛榜单是一个 2 行 n 列的表格&#xff1a; 第一行是 n 个大写字母&#…

用git下载vcpkg时出现Connection was reset时的处理

用git安装vcpkg时出现Connect was rest&#xff08;如上图&#xff09;。多谢这位网友的博文解决了问题&#xff1a; 通过:http.sslVerify false全局来设置&#xff0c;执行以下命令&#xff1a; git config --global http.sslVerify "false" 原文链接&#xff1a…

leetcode - 滑动窗口问题集

目录 前言 题1 长度最小的子数组&#xff1a; 思考&#xff1a; 参考代码1&#xff1a; 参考代码2&#xff1a; 题2 无重复字符的最长子串&#xff1a; 思考&#xff1a; 参考代码1&#xff1a; 参考代码2&#xff1a; 题3 最大连续1的个数 III&#xff1a; 思考&am…

一分钟在Cherry Studio和VSCode集成火山引擎veimagex-mcp

MCP的出现打通了AI模型和外部数据库、网页API等资源&#xff0c;成倍提升工作效率。近期火山引擎团队推出了 MCP Server SDK&#xff1a; veimagex-mcp。本文介绍如何在Cherry Studio 和VSCode平台集成 veimagex-mcp。 什么是MCP MCP&#xff08;Model Context Protocol&…