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

发布于:2025-05-14 ⋅ 阅读:(12) ⋅ 点赞:(0)

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

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


网站公告

今日签到

点亮在社区的每一天
去签到