通过 Caffeine 和 Spring Cache 的集成,实现高性能的本地缓存

简介

Spring @Cacheable 注解

@Cacheable 是什么

@Cacheable 是 Spring Framework 提供的一个注解,用于方法级别的缓存管理。当一个被标注为 @Cacheable 的方法被调用时,它会先检查缓存中是否有对应的结果。如果有,则直接返回缓存结果,而不会执行方法逻辑。如果没有,则执行方法逻辑并将结果存入缓存,以便下次调用时直接使用缓存值。


作用

  1. 提升性能:避免重复调用耗时的计算或 I/O 操作(如数据库查询或远程调用)。
  2. 减少资源消耗:减少系统对外部依赖(如数据库、API)的访问频率。
  3. 简单易用:通过注解配置,无需显式管理缓存逻辑。

参数解析

java 复制代码
@Cacheable(
    cacheNames = ..., // 缓存的名字(可理解为缓存的分类)
    key = ...,        // 缓存的键(默认使用方法参数作为键)
    unless = ...,     // 条件表达式,返回 true 时不会缓存
    condition = ...   // 条件表达式,返回 true 时才缓存
)
  • cacheNames: 指定缓存名称,用于区分不同的缓存空间。
  • key: 自定义缓存键的生成规则,支持 SpEL(Spring Expression Language)。
  • unless: 返回结果满足条件时,不存入缓存。
  • condition: 满足条件时,才会存入缓存。
  • sync : 如果为 true,则多个线程同时访问会先锁定,确保只执行一次计算。

Caffeine 本地缓存

Caffeine 是一个高性能、本地缓存库,提供类似于 Guava Cache 的功能,并且性能更优。想了解跟多可以自行百度,这里不做过多介绍哈(感谢支持)

Caffeine 和 Spring Cache 实现本地缓存

1. 添加 Maven 依赖

pom.xml 中添加以下依赖:

xml 复制代码
<dependencies>
    <!-- Spring Cache Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <!-- Caffeine Cache -->
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
        <version>3.1.7</version> <!-- 使用最新稳定版本 -->
    </dependency>
</dependencies>

2.配置类 LocalCacheConfig

java 复制代码
import com.github.benmanes.caffeine.cache.Caffeine;
import com.atom.utils.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

@Configuration
public class LocalCacheConfig {

    public final static String PRODUCT_CACHE = "PRODUCT_CACHE";

    @Bean
    public Cache flashRedisFallbackCache(CacheManager cacheManager) {
        CaffeineCache localCache = new CaffeineCache(PRODUCT_CACHE, Caffeine.newBuilder()
                .recordStats()
                .expireAfterWrite(300, TimeUnit.SECONDS)
                .initialCapacity(10000)
                .maximumSize(10000).build());
        reInitCacheManager(cacheManager, localCache);
        return localCache;
    }

    /**
     * SimpleCacheManager 中的缓存实例是初始化时一次性加载的,需要重新初始化一下CacheManager,将自定义cache池加入CacheManager
     */
    private void reInitCacheManager(CacheManager cacheManager, Cache cache) {
        SimpleCacheManager simpleCacheManager = (SimpleCacheManager) cacheManager;
        Collection<String> cacheNames = simpleCacheManager.getCacheNames();
        ArrayList<Cache> caches = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(cacheNames)) {
            cacheNames.forEach(cacheName -> caches.add(simpleCacheManager.getCache(cacheName)));
        }
        caches.add(cache);
        ((SimpleCacheManager) cacheManager).setCaches(caches);
        ((SimpleCacheManager) cacheManager).initializeCaches();
    }
}

3. 在业务方法中使用缓存注解

使用 Spring 提供的缓存注解(如 @Cacheable@CachePut@CacheEvict)来实现缓存的读写操作。

示例 1: 使用 @Cacheable

java 复制代码
@Service
public class ProductService {

    @Cacheable(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId")
    public ProductDTO getProductById(String productId) {
        // 模拟查询数据库
        return productRepository.findProductById(productId);
    }
}

示例 2: 更新缓存 (@CachePut)

java 复制代码
@CachePut(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId.id")
public ProductDTO updateProduct(ProductDTO product) {
    productRepository.updateProduct(product);
    return product;
}

示例 3: 清除缓存 (@CacheEvict)

java 复制代码
@CacheEvict(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId")
public void deleteProduct(String productId) {
    productRepository.deleteProductById(productId);
}

4. 验证缓存是否生效

验证缓存时,可以通过以下方式检查:

  1. 日志输出 :启用 Spring Cache 的 debug 日志,查看缓存操作的记录。

    application.yml 中添加:

    yaml 复制代码
    logging:
      level:
        org.springframework.cache: DEBUG
  2. 统计信息 :通过 Caffeine.newBuilder().recordStats() 启用统计信息,并使用以下代码查看缓存命中率等:

    java 复制代码
    CaffeineCache storeCache = (CaffeineCache) cacheManager.getCache("STORE_CACHE");
    System.out.println(storeCache.getNativeCache().stats());

总结

通过 Caffeine 和 Spring Cache 的集成简单易用,通过注解配置,无需显式管理缓存逻辑。在调用数据的方法上加可以减少重复调用问题,降低被调用方的压力,也可结合 Redis 快速实现多级缓存,解决热点数据问题。更多妙用,开发者可以继续探索,感谢支持,下期再见👋

相关推荐
华子w9089258592 分钟前
基于Java+SpringMvc+Vue技术的宠物分享平台
java·开发语言·宠物
白宇横流学长7 分钟前
基于Java的推箱子游戏设计与实现
java·python·游戏
baozhengw7 分钟前
SpringBoot项目实战(41)--Beetl网页使用自定义函数获取新闻列表
java·前端·spring boot
程序员老石14 分钟前
Clickhouse基础(一)
java·开发语言·clickhouse
qq_4130661036 分钟前
tdengine数据库使用java连接
java·数据库·tdengine
快乐就好ya2 小时前
win下搭建elk并集成springboot
java·spring boot·后端·spring·elk·spring cloud
S-X-S3 小时前
AOP实现操作日志记录
java·junit·aop
温柔了岁月.c3 小时前
SpringAop
java·spring aop·动态代理·切面编程
firepation3 小时前
基于 SpringBoot线上考试系统的设计与实现
java·spring boot·mysql·源码·课程设计