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

[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.xmltype: 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 {@Autowiredprivate 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 {@Beanpublic 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 {@Autowiredprivate ProductService productService;@Autowiredprivate ProductMapper productMapper;@Autowiredprivate CacheManager cacheManager;@Testpublic 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());}@Testpublic 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());}@Testpublic 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.mzph.cn/pingmian/81063.shtml

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

相关文章

LlamaIndex 第九篇 Indexing索引

索引概述 数据加载完成后&#xff0c;您将获得一个文档对象(Document)列表&#xff08;或节点(Node)列表&#xff09;。接下来需要为这些对象构建索引(Index)&#xff0c;以便开始执行查询。 索引&#xff08;Index&#xff09; 是一种数据结构&#xff0c;能够让我们快速检索…

【问题排查】easyexcel日志打印Empty row!

问题原因 日志打印​​I/O 操作开销​&#xff08;如 Log4j 的 FileAppender&#xff09;会阻塞业务线程&#xff0c;直到日志写入完成&#xff0c;导致接口响应变慢 问题描述 在线上环境&#xff0c;客户反馈导入一个不到1MB的excel文件&#xff0c;耗时将近5分钟。 问题排…

代码随想录第51天|岛屿数量(深搜)、岛屿数量(广搜)、岛屿的最大面积

1.岛屿数量&#xff08;深搜&#xff09; ---》模板题 版本一写法&#xff1a;下一个节点是否能合法已经判断完了&#xff0c;传进dfs函数的就是合法节点。 #include <iostream> #include <vector> using namespace std;int dir[4][2] {0, 1, 1, 0, -1, 0, 0, -…

Made with Unity | 从影视到游戏:《鱿鱼游戏》IP 的边界拓展

优质IP的跨媒体开发潜力不可限量。以现象级剧集《鱿鱼游戏》为例&#xff0c;Netflix旗下游戏工作室Boss Fight在第二季开播前夕推出的手游《Squid Game: Unleashed》&#xff0c;一经发布便横扫全球107个国家和地区的App Store免费游戏榜首。 这款多人派对大逃杀游戏完美还原…

allure 报告更改标题和语言为中文

在网上看到好多谈到更改allure 的标题设置都很麻烦&#xff0c;去更改JSON文件 其实可以有更简单的办法&#xff0c;就是在生成报表时增加参数 使用allure --help 查看&#xff1a; --lang, --report-language 设置报告的语言&#xff0c;默认是应用 The report language. …

HGDB索引膨胀的检查与处理思路

文章目录 环境文档用途详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5.8 文档用途 本文档主要介绍HGDB索引膨胀的定义、产生的原因、如何检查以及遇到索引膨胀如何处理&#xff08;包括预防和解决&#xff09; 详细信息 …

【Python CGI编程】

Python CGI&#xff08;通用网关接口&#xff09;编程是早期Web开发中实现动态网页的技术方案。以下是系统化指南&#xff0c;包含核心概念、实现步骤及安全实践&#xff1a; 一、CGI 基础概念 1. 工作原理 浏览器请求 → Web服务器&#xff08;如Apache&#xff09; → 执行…

数据库故障排查指南:从入门到精通

1. 常见数据库故障类型 1.1 连接故障 数据库连接超时连接池耗尽网络连接中断认证失败1.2 性能故障 查询执行缓慢内存使用过高CPU使用率异常磁盘I/O瓶颈1.3 数据故障 数据不一致数据丢失数据损坏事务失败2. 故障排查流程 2.1 初步诊断 -- 检查数据库状态SHOW STATUS;SHOW PRO…

conda创建环境常用命令(个人用)

创建环境 conda create --name your_project_name创建环境 ---- 指定环境python版本 conda create --name your_project_name python3.x环境列表 conda env list激活环境 conda activate your_project_name退出环境 conda deactivate环境列表 #使用conda命令 conda list …

PCL 绘制二次曲面

文章目录 一、简介二、实现代码三、实现效果一、简介 这里基于二次曲面的公式: z = a 0 + a 1 x + a 2 y + a

一文讲透面向对象编程OOP特点及应用场景

面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;是一种以对象为核心、通过类组织代码的编程范式。它通过模拟现实世界的实体和交互来构建软件系统&#xff0c;是现代软件开发中最广泛使用的范式之一。以下是 OOP 的全面解析&#xff1a; 一、OOP 的四大…

linux,我启动一个springboot项目, 用java -jar xxx.jar ,但是没多久这个java进程就会自动关掉

当使用 java -jar xxx.jar & 启动 Spring Boot 项目后进程自动关闭时&#xff0c;可能由多种原因导致。以下是常见排查步骤和解决方案&#xff1a; 一、查看日志定位原因 进程异常关闭通常会在控制台或日志中留下线索&#xff0c;建议先获取完整日志&#xff1a; 1. 查看…

【独家精简】win11(24h2)清爽加速版

自作该版本的初心&#xff1a;随着电脑性能的不断提升&#xff0c;我们需要的更多的是没有广告&#xff0c;没有推荐&#xff0c;没有收集隐私的windows清爽版纯净系统 目前只会去制作windows系统专业版 1、去除Windows系统自带的广告新闻和推荐以及小组间和聊天功能。 2、精简…

大二java第一面小厂(挂)

第一场&#xff1a; mybatis怎么防止数据转义。 Hutool用的那些你常用的方法。 springboot的常用注解。 redis的多级缓存。 websocket怎么实现的多人协作编辑功能。 怎么实现的分库分表。 mysql里面的各种操作&#xff0c;比如说分表怎么分&#xff0c;分页查询怎么用。 mybat…

OceanBase 的系统变量、配置项和用户变量有何差异

在继续阅读本文之前&#xff0c;大家不妨先思考一下&#xff0c;数据库中“系统变量”、“用户变量”以及“配置项”这三者之间有何不同。如果感到有些模糊&#xff0c;那么本文将是您理清这些概念的好帮手。 很多用户在使用OceanBase数据库中的“配置项”和“系统变量”&#…

HTML-3.3 表格布局(学校官网简易布局实例)

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 系列文章目录 HTML-1.1 文本字体样式-字体设置、分割线、段落标签、段内回车以及特殊符号 HTML…

如何在Edge浏览器里-安装梦精灵AI提示词管理工具

方案一&#xff08;应用中心安装-推荐&#xff09;&#xff1a; 梦精灵 跨平台AI提示词管理工具 - Microsoft Edge AddonsMake Microsoft Edge your own with extensions that help you personalize the browser and be more productive.https://microsoftedge.microsoft.com…

GpuGeek 网络加速:破解 AI 开发中的 “最后一公里” 瓶颈

摘要&#xff1a; 网络延迟在AI开发中常被忽视&#xff0c;却严重影响效率。GpuGeek通过技术创新&#xff0c;提供学术资源访问和跨国数据交互的加速服务&#xff0c;助力开发者突破瓶颈。 目录 一、引言&#xff1a;当算力不再稀缺&#xff0c;网络瓶颈如何破局&#xff1f; …

校园社区小程序源码解析

基于ThinkPHP、FastAdmin和UniApp开发的校园社区小程序源码&#xff0c;旨在为校园内的学生和教职员工提供一个便捷的在线交流和服务平台。 该小程序前端采用UniApp进行开发&#xff0c;具有良好的跨平台兼容性&#xff0c;可以轻松发布到iOS和Android平台。同时&#xff0c;后…

【Elasticsearch】flattened`类型在查询嵌套数组时可能返回不准确结果的情况

好的&#xff01;为了更清楚地说明flattened类型在查询嵌套数组时可能返回不准确结果的情况&#xff0c;我们可以通过一个具体的例子来展示。这个例子将展示如何在文档中没有完全匹配的嵌套对象时&#xff0c;flattened类型仍然可能返回该文档。 示例文档结构 假设你有以下文…