Spring Boot中集成Guava Cache或者Caffeine

一、在Spring Boot(1.x版本)中集成Guava Cache

注意: Spring Boot 2.x+用户:优先使用Caffeine,性能更优且维护活跃。

1. 添加依赖

pom.xml中添加Guava依赖:

xml 复制代码
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version> <!-- 使用最新版本 -->
</dependency>

2. 启用缓存支持

在启动类上添加@EnableCaching注解:

java 复制代码
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. 配置Guava缓存管理器

创建配置类定义CacheManager Bean:

java 复制代码
@Configuration
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        GuavaCacheManager cacheManager = new GuavaCacheManager();
        cacheManager.setCacheBuilder(CacheBuilder.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES) // 写入10分钟后过期
                .maximumSize(100) // 最大缓存数量
                .recordStats()); // 开启统计信息
        return cacheManager;
    }
}

4. 使用缓存注解

在Service层使用@Cacheable@CacheEvict等注解:

java 复制代码
@Service
public class UserService {
 	// 缓存查询结果,key为id
    @Cacheable(value = "USER_CACHE", key = "#id")
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    // 更新缓存
    @CachePut(value = "USER_CACHE", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }

    // 删除缓存
    @CacheEvict(value = "USER_CACHE", key = "#id")
    public void deleteUser(Long id) {
    // 删除用户逻辑
        userRepository.deleteById(id);
    }

}

5. 验证缓存效果

编写测试类或调用接口验证缓存是否生效:

java 复制代码
@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testCache() {
        // 第一次调用,执行方法
        User user1 = userService.getUserById("123");
        // 第二次调用,从缓存获取
        User user2 = userService.getUserById("123");
        // 验证是否为同一对象(缓存生效)
        assertThat(user1).isSameAs(user2);
    }
}

高级配置

  • 多缓存配置:为不同缓存设置不同策略:

    java 复制代码
    @Bean
    public CacheManager cacheManager() {
        GuavaCacheManager cacheManager = new GuavaCacheManager();
        cacheManager.setCacheBuilder(CacheBuilder.newBuilder()
                .expireAfterWrite(30, TimeUnit.MINUTES)
                .maximumSize(500));
        cacheManager.setCacheBuilder("userCache", CacheBuilder.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(100));
        return cacheManager;
    }
  • 刷新策略 :使用refreshAfterWrite定时刷新(需配合LoadingCache):

    java 复制代码
    CacheBuilder.newBuilder()
        .refreshAfterWrite(5, TimeUnit.MINUTES)
        .build(CacheLoader.from(key -> loadData(key)));
  • 统计信息 :通过recordStats()启用统计,使用cache.getStatistics()获取命中率等信息。

常见问题

  1. 缓存未生效

    • 确保启动类有@EnableCaching
    • 检查方法是否为public(注解在私有方法上无效)。
  2. 配置未应用

    • 确认CacheManager Bean正确注册。
    • 检查缓存名称是否匹配@Cacheable(value = "cacheName")
  3. 内存溢出

    • 合理设置maximumSizeexpireAfterAccess/Write

通过以上步骤,即可在Spring Boot中高效使用Guava Cache实现本地缓存,提升应用性能。



二、Spring Boot 2.x及以上版本(推荐使用Caffeine)

在Spring Boot 2.x及以上版本中,Caffeine作为默认的本地缓存组件,取代了Guava Cache,提供了更高的性能和更灵活的配置。


1. 添加依赖

需引入spring-boot-starter-cachecaffeine依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version> <!-- 推荐使用最新版本 -->
</dependency>

2. 启用缓存支持

在启动类添加@EnableCaching注解:

java 复制代码
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. 配置Caffeine缓存

方式一:通过配置文件

application.yml中定义全局缓存参数:

yaml 复制代码
spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=500,expireAfterWrite=600s,initialCapacity=100
    cache-names: userCache, productCache  # 定义缓存名称
  • 常用参数
    • maximumSize:最大缓存条目数
    • expireAfterWrite:写入后过期时间
    • initialCapacity:初始容量。
方式二:通过Java Config类

为不同缓存设置独立策略(推荐多缓存场景):

java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {
    public enum Caches {
        USER_CACHE(600, 1000),  // 有效期600秒,最大容量1000
        PRODUCT_CACHE(3600);
        
        private final int ttl;
        private final int maxSize;

        Caches(int ttl, int maxSize) {
            this.ttl = ttl;
            this.maxSize = maxSize;
        }
        public int getTtl() {
            return ttl;
        }

        public int getMaxSize() {
            return maxSize;
        }
    }

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager manager = new SimpleCacheManager();
        List<CaffeineCache> caches = Arrays.stream(Caches.values())
                .map(c -> new CaffeineCache(c.name(), Caffeine.newBuilder()
                        .expireAfterWrite(c.getTtl(), TimeUnit.SECONDS)
                        .maximumSize(c.getMaxSize())
                        .build()))
                .collect(Collectors.toList());
        manager.setCaches(caches);
        return manager;
    }
}

此方式支持为每个缓存单独配置过期时间和容量。


4. 使用缓存注解

在Service层通过注解操作缓存:

java 复制代码
@Service
public class UserService {
    // 缓存查询结果,key为id
    @Cacheable(value = "USER_CACHE", key = "#id")
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    // 更新缓存
    @CachePut(value = "USER_CACHE", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }

    // 删除缓存
    @CacheEvict(value = "USER_CACHE", key = "#id")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}
  • 注解说明
    • @Cacheable:查询时优先从缓存读取
    • @CachePut:更新数据并刷新缓存
    • @CacheEvict:删除数据时移除缓存。

5. 高级配置

刷新策略(RefreshAfterWrite)

需定义CacheLoader以支持自动刷新:

java 复制代码
@Bean
public CacheLoader<Object, Object> cacheLoader() {
    return new CacheLoader<>() {
        @Override
        public Object load(Object key) {
            return loadDataFromDB(key);  // 初始加载数据
        }
        @Override
        public Object reload(Object key, Object oldValue) {
            return oldValue;  // 刷新时保留旧值,异步加载新值
        }
    };
}

配置文件中需添加refreshAfterWrite=5s,并关联此Bean。

统计与监控

启用统计功能:

java 复制代码
Caffeine.newBuilder()
    .recordStats()
    .build();

通过cache.stats()获取命中率、回收数量等指标。


6. 验证缓存效果

通过测试类验证缓存是否生效:

java 复制代码
@SpringBootTest
public class CacheTest {
    @Autowired
    private UserService userService;

    @Test
    public void testCache() {
        User user1 = userService.getUserById(1L);  // 首次查询,存入缓存
        User user2 = userService.getUserById(1L);  // 二次查询,命中缓存
        assertThat(user1).isSameAs(user2);
    }
}

常见问题

  1. 缓存未命中

    • 检查方法是否为public(注解在私有方法无效)
    • 确认缓存名称与配置一致。
  2. 配置冲突

    • 避免同时配置maximumSizemaximumWeight
    • expireAfterWrite优先级高于expireAfterAccess

通过以上步骤,可在Spring Boot 2.x中高效集成Caffeine,实现高性能本地缓存,适用于高频访问但更新较少的数据场景(如配置信息、静态数据)。



三、Caffeine使用场景

Caffeine 作为高性能本地缓存库,适用于多种需要快速数据访问和高效内存管理的场景。以下是其主要使用场景及对应的技术优势分析:


1. 高并发请求缓存

  • 场景描述:适用于高频访问的接口或热点数据,例如用户信息查询、商品详情展示等。Caffeine 通过无锁并发设计和 Window TinyLFU 算法,显著提升缓存命中率,减少数据库压力。
  • 技术优势
    • 高性能:在高并发环境下,Caffeine 的吞吐量远超 Guava Cache,其分段锁机制避免了锁竞争问题。
    • 高命中率:Window TinyLFU 算法结合 LRU 和 LFU 优点,有效保留高频访问数据,命中率比 Guava 提升 10%~20%。
  • 典型应用:Web 应用的 API 接口缓存,如电商平台的商品详情页。

2. 数据库查询缓存

  • 场景描述:用于缓存频繁查询的数据库结果,如用户常用配置、热门商品库存等,减少重复数据库访问。
  • 技术优势
    • 自动过期策略 :支持 expireAfterWrite(写入后过期)和 expireAfterAccess(访问后过期),防止数据过时。
    • 内存管理 :通过 maximumSize 限制缓存条目数,避免内存溢出,结合惰性删除和定时清理机制优化内存使用。
  • 典型应用:用户登录信息缓存、商品库存实时查询缓存。

3. 复杂计算结果缓存

  • 场景描述:缓存计算密集型操作的结果,如图像处理、大数据聚合分析等,避免重复计算消耗资源。
  • 技术优势
    • 异步加载 :通过 AsyncLoadingCache 异步加载数据,减少主线程阻塞,提升系统响应速度。
    • 刷新机制 :使用 refreshAfterWrite 定时刷新缓存,保证数据更新后的及时性,同时保留旧数据直至新数据加载完成。
  • 典型应用:推荐系统的实时计算结果缓存、图像处理后的缩略图缓存。

4. 多级缓存架构(L1缓存)

  • 场景描述:在分布式系统中作为一级本地缓存(L1),结合 Redis(L2)和数据库(L3)形成三级缓存,减少跨服务或跨节点的网络延迟。
  • 技术优势
    • 低延迟访问:本地内存访问速度极快,适合对延迟敏感的场景。
    • 灵活集成 :通过 CacheLoaderWriter 接口,可无缝与 Redis 等外部缓存联动,实现数据回源和同步。
  • 典型应用:秒杀系统的库存缓存、分布式服务中的配置信息缓存。

5. 需要高灵活性和统计监控的场景

  • 场景描述:对缓存策略有定制化需求(如动态调整过期时间、监听缓存事件)或需监控缓存命中率的场景。
  • 技术优势
    • 灵活配置:支持基于大小、时间、引用等多种淘汰策略,并可自定义过期逻辑。
    • 统计功能 :通过 recordStats() 启用统计,获取命中率、淘汰次数等指标,便于性能调优。
  • 典型应用:实时监控系统的缓存健康状态、需要动态调整缓存策略的业务场景。

注意事项

  1. 非分布式场景:Caffeine 仅适用于本地缓存,跨节点数据需结合 Redis 等分布式缓存。
  2. 内存限制 :需根据应用内存合理设置 maximumSize 或权重,避免 OOM 问题。
  3. 数据一致性:本地缓存可能导致多实例间数据不一致,需通过过期时间或事件通知机制解决。

总结

Caffeine 凭借其高性能、高命中率和灵活的配置,成为高并发、低延迟场景下的首选本地缓存库。尤其适合作为一级缓存与 Redis 等组成多级缓存架构,或用于需要快速响应和复杂策略管理的业务场景。实际应用中需结合具体需求调整淘汰策略和内存配置,以最大化其优势。

更多用法:

SpringBoot:第五篇 集成Guava(本地缓存+分布式缓存)

相关推荐
耀耀_很无聊2 小时前
02_使用 AES 算法实现文件加密上传至阿里云、解密下载
java·spring boot·算法·阿里云·云计算·aes·oss
GalaxySpaceX2 小时前
Hibernate-Core (CVE-2020-25638)
java·spring·hibernate
小钻风巡山4 小时前
springboot 视频分段加载在线播放
java·spring boot·后端
江沉晚呤时4 小时前
Redis缓存穿透、缓存击穿与缓存雪崩:如何在.NET Core中解决
java·开发语言·后端·算法·spring·排序算法
hello_ejb36 小时前
聊聊Spring AI Alibaba的MermaidGenerator
人工智能·python·spring
-曾牛6 小时前
开启 Spring AI 之旅:从入门到实战
java·人工智能·spring·指南·教学·大模型应用·springai
汐栊8 小时前
Redis总结及设置营业状态案例
java·redis·spring
hac13228 小时前
SpringBoot多环境配置
java·spring boot·后端
lllsure9 小时前
SpringCloud组件——Gateway
spring·spring cloud·gateway
猿来入此小猿10 小时前
基于SpringBoot+Vue实现的电影推荐平台功能一
vue.js·spring boot·毕业设计·毕业源码·免费学习·猿来入此·电影推荐平台