Spring Boot集成Caffeine本地缓存完整方案

发布于:2025-07-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

Spring Boot集成Caffeine本地缓存完整方案

以下是基于您项目架构的Caffeine本地缓存集成方案,包含依赖配置、缓存策略和使用示例,适配DDD架构设计。

一、添加依赖

/pom.xml中添加Caffeine依赖:


<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
二、缓存配置类

创建Caffeine缓存配置类,放在基础设施层:


package cn.bugstack.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching // 启用缓存功能
public class CacheConfig {

    /**
     * 配置Caffeine缓存管理器
     */
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        // 默认缓存配置
        cacheManager.setCaffeine(defaultCacheConfig());
        return cacheManager;
    }

    /**
     * 自定义缓存配置(多策略)
     */
    @Bean
    public Caffeine<Object, Object> defaultCacheConfig() {
        return Caffeine.newBuilder()
                .maximumSize(10_000) // 最大缓存条目
                .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后过期时间
                .recordStats() // 启用统计功能
                .evictionListener((key, value, cause) -> {
                    // 缓存驱逐监听器(可选)
                    // log.info("Cache evicted - key:{}, cause:{}", key, cause);
                });
    }

    /**
     * 商品缓存配置(特定策略)
     */
    @Bean
    public Caffeine<Object, Object> productCacheConfig() {
        return Caffeine.newBuilder()
                .maximumSize(5_000)
                .expireAfterWrite(5, TimeUnit.MINUTES) // 商品缓存5分钟过期
                .recordStats();
    }

    /**
     * 用户缓存配置(特定策略)
     */
    @Bean
    public Caffeine<Object, Object> userCacheConfig() {
        return Caffeine.newBuilder()
                .maximumSize(20_000)
                .expireAfterAccess(30, TimeUnit.MINUTES) // 访问后过期
                .recordStats();
    }
}
三、多缓存策略配置(可选)

如需为不同业务场景配置差异化缓存策略:

// 在CacheConfig中添加
@Bean
public CacheManager cacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager();
    // 为不同缓存名称配置不同策略
    Map<String, Caffeine<Object, Object>> cacheMap = new HashMap<>();
    cacheMap.put("productCache", productCacheConfig());
    cacheMap.put("userCache", userCacheConfig());
    cacheMap.put("activityCache", activityCacheConfig());
    cacheManager.setCacheSpecification(cacheMap);
    return cacheManager;
}

// 活动缓存配置
public Caffeine<Object, Object> activityCacheConfig() {
    return Caffeine.newBuilder()
            .maximumSize(1_000)
            .expireAfterWrite(1, TimeUnit.HOURS)
            .recordStats();
}
四、Service层缓存使用示例

在领域服务中应用缓存:

// 文件路径: d:\develop\workspace\big-market\big-market-domain\src\main\java\cn\bugstack\domain\service\ProductService.java
package cn.bugstack.domain.service;

import cn.bugstack.domain.model.ProductInfo;
import cn.bugstack.domain.repository.ProductRepository;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class ProductService {

    @Resource
    private ProductRepository productRepository;

    /**
     * 查询商品信息(使用商品缓存策略)
     */
    @Cacheable(value = "productCache", key = "#productId", unless = "#result == null")
    public ProductInfo getProductById(Long productId) {
        // 实际业务中可能包含复杂查询或计算
        return productRepository.selectById(productId);
    }

    /**
     * 更新商品信息(更新缓存)
     */
    @CachePut(value = "productCache", key = "#product.id")
    public ProductInfo updateProduct(ProductInfo product) {
        return productRepository.update(product);
    }

    /**
     * 删除商品(清除缓存)
     */
    @CacheEvict(value = "productCache", key = "#productId")
    public void deleteProduct(Long productId) {
        productRepository.deleteById(productId);
    }

    /**
     * 清除所有商品缓存
     */
    @CacheEvict(value = "productCache", allEntries = true)
    public void clearProductCache() {
        // 仅用于清除缓存,无需业务逻辑
    }
}
五、缓存统计与监控
  1. 启用统计后获取缓存指标
@Service
public class CacheStatsService {

    @Resource
    private CacheManager cacheManager;

    public CacheStats getProductCacheStats() {
        CaffeineCache cache = (CaffeineCache) cacheManager.getCache("productCache");
        return cache.getNativeCache().stats();
    }

    // 暴露监控端点
    public Map<String, Object> getCacheMetrics() {
        Map<String, Object> metrics = new HashMap<>();
        CacheStats stats = getProductCacheStats();
        metrics.put("hitRate", stats.hitRate());
        metrics.put("missCount", stats.missCount());
        metrics.put("evictionCount", stats.evictionCount());
        return metrics;
    }
}
  1. 集成Actuator监控(可选):
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: cache,health,info
六、与Redis多级缓存集成(推荐)

结合项目已有的Redis热点隔离方案,实现多级缓存:

@Service
public class ProductServiceImpl implements ProductService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private ProductRepository productRepository;

    @Override
    public ProductInfo getProductById(Long productId) {
        // 1. 先查本地缓存
        ProductInfo product = getProductFromLocalCache(productId);
        if (product != null) {
            return product;
        }

        // 2. 再查Redis缓存
        product = getProductFromRedis(productId);
        if (product != null) {
            // 回填本地缓存
            putProductToLocalCache(product);
            return product;
        }

        // 3. 最后查数据库
        product = productRepository.selectById(productId);
        if (product != null) {
            // 写入Redis和本地缓存
            putProductToRedis(product);
            putProductToLocalCache(product);
        }
        return product;
    }

    // 本地缓存操作(使用Caffeine API直接操作)
    private ProductInfo getProductFromLocalCache(Long productId) {
        // 实现略
    }
}
七、关键配置参数说明
参数 作用 推荐值
maximumSize 最大缓存条目 10,000-100,000(根据内存)
expireAfterWrite 写入后过期时间 5-30分钟(根据数据更新频率)
expireAfterAccess 访问后过期时间 30-120分钟(不常访问数据)
recordStats 启用统计 true(便于监控调优)
initialCapacity 初始容量 100-1000(减少扩容开销)
八、最佳实践
  1. 缓存粒度

    • 缓存完整领域对象而非零散数据
    • 对大对象进行拆分缓存(如商品基本信息和详情分开)
  2. 更新策略

    • 读多写少场景用@Cacheable
    • 写频繁场景考虑Cache Aside Pattern
  3. 防缓存穿透

    @Cacheable(value = "productCache", key = "#productId", unless = "#result == null")
    
  4. 缓存预热

    @PostConstruct
    public void preloadCache() {
        List<Long> hotProductIds = Arrays.asList(1001L, 1002L, 1003L);
        hotProductIds.forEach(this::getProductById);
    }
    

该方案已适配您项目的DDD架构,缓存配置放在基础设施层,业务逻辑通过注解使用缓存,既保持了代码整洁又实现了高性能本地缓存。可根据实际业务需求调整缓存策略参数。


网站公告

今日签到

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