当前位置: 首页 > news >正文

[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 官方文档

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

相关文章:

  • Centos7安装部署wordpress个人博客保姆级教程
  • window 显示驱动开发-报告图形内存(一)
  • typedef unsigned short uint16_t; typedef unsigned int uint32_t;
  • ‌C# 集成 FastDFS 完整指南‌
  • C++ string数据查找、string数据替换、string子串获取
  • MySQL 数据库:创建新数据库和数据表全攻略
  • 在Ubuntu服务器上部署Label Studio
  • 蓝桥杯13届国B 出差
  • 软件产品线上验收测试有什么目的?又有哪些测试流程?
  • Java接口性能优化:零成本实现数据库状态到中文的极致转换
  • 【图像处理基石】遥感图像分析入门
  • 硬件自动化测试平台搭建(硅后验证,非EDA)day1 大概了解
  • 【报错解决】服务器重启后vscode远程连接失败
  • ‌Element UI 双击事件(@cell-dblclick 与 @row-dblclick)
  • 使用java通过modbus读取前端设备数据
  • AI Agent开发第65课-DIFY和企业现有系统结合实现高可配置的智能零售AI Agent(下)
  • 【Python爬虫 !!!!!!政府招投标数据爬虫项目--医疗实例项目文档(提供源码!!!)!!!学会Python爬虫轻松赚外快】
  • 现代化QML组件开发教程
  • 支付宝小程序开发指南
  • 在Babylon.js中实现完美截图:包含Canvas和HTML覆盖层
  • 颜福庆与顾临的争论:1930年代在中国维持一家医学院要花多少钱
  • 七旬男子驾“老头乐”酒驾被查,曾有两次酒驾两次肇事记录
  • 反制美国钢铝关税!印度拟对美国部分商品征收关税
  • 训练孩子的科学思维,上海虹口推出“六个一百”旗舰工程
  • 旭辉控股集团主席林中:债务重组是活下来的前提,自营开发业务收缩至少数核心城市
  • 影子调查丨三名“淘金客”殒命雪峰山:千余废弃金矿洞的监管难题