Guava Cache 本地项目缓存

  1. 添加依赖

在 Spring Boot 项目中,Guava Cache 是 Google Guava 库的一部分,因此需要添加 Guava 的依赖。

在 pom.xml(Maven)中添加以下依赖:

xml

xml 复制代码
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.3.1-jre</version>
</dependency>

注意 : 请根据需要选择最新版本,检查 Maven Central 获取最新版本号。

如果使用 Gradle,可以在 build.gradle 中添加:

gradle

text 复制代码
implementation 'com.google.guava:guava:33.3.1-jre'

  1. 创建 Guava Cache 配置

Guava Cache 需要手动配置缓存实例,包括缓存大小、过期策略等。以下是一个简单的配置类,展示如何在 Spring Boot 中定义 Guava Cache。

java

java 复制代码
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class GuavaCacheConfig {

    @Bean
    public LoadingCache<String, String> guavaCache() {
        return CacheBuilder.newBuilder()
                .maximumSize(1000) // 最大缓存条目数
                .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
                .expireAfterAccess(5, TimeUnit.MINUTES) // 访问后5分钟过期
                .recordStats() // 开启统计信息(如命中率)
                .build(new CacheLoader<String, String>() {
                    @Override
                    public String load(String key) throws Exception {
                        // 当缓存未命中时,调用此方法加载数据
                        return loadDataFromSource(key);
                    }
                });
    }

    // 模拟从数据源加载数据
    private String loadDataFromSource(String key) {
        // 实际场景中,这里可能从数据库或外部服务加载数据
        return "Value for " + key;
    }
}

说明:

  • maximumSize: 设置缓存最大条目数,超出时按 LRU(最近最少使用)策略淘汰。
  • expireAfterWrite: 写入后指定时间过期。
  • expireAfterAccess: 最后访问后指定时间过期。
  • recordStats: 开启统计功能,可用于监控缓存命中率。
  • CacheLoader: 定义未命中时的加载逻辑(例如从数据库查询)。

  1. 在 Service 层中使用 Guava Cache

将配置好的 Guava Cache 注入到业务逻辑中,并在需要的地方使用缓存。

以下是一个简单的 Service 示例:

java

java 复制代码
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DataService {

    @Autowired
    private LoadingCache<String, String> guavaCache;

    public String getData(String key) {
        try {
            // 从缓存中获取数据,如果未命中则通过 CacheLoader 加载
            return guavaCache.get(key);
        } catch (Exception e) {
            // 处理异常
            return "Error retrieving data for key: " + key;
        }
    }

    public void putData(String key, String value) {
        // 手动放入缓存
        guavaCache.put(key, value);
    }

    public void invalidate(String key) {
        // 移除缓存中的键
        guavaCache.invalidate(key);
    }

    public void printCacheStats() {
        // 打印缓存统计信息
        System.out.println("Cache Stats: " + guavaCache.stats());
    }
}

说明:

  • guavaCache.get(key): 尝试从缓存中获取数据,未命中时会触发 CacheLoader 的 load 方法。
  • guavaCache.put(key, value): 手动将数据放入缓存。
  • guavaCache.invalidate(key): 移除指定键的缓存。
  • guavaCache.stats(): 查看缓存的命中率、加载时间等统计信息。

  1. 在 Controller 中调用

创建一个简单的 REST Controller 来测试缓存功能。

java

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/cache")
public class CacheController {

    @Autowired
    private DataService dataService;

    @GetMapping("/get/{key}")
    public String getData(@PathVariable String key) {
        return dataService.getData(key);
    }

    @PostMapping("/put")
    public String putData(@RequestParam String key, @RequestParam String value) {
        dataService.putData(key, value);
        return "Data stored in cache";
    }

    @DeleteMapping("/invalidate/{key}")
    public String invalidate(@PathVariable String key) {
        dataService.invalidate(key);
        return "Cache invalidated for key: " + key;
    }

    @GetMapping("/stats")
    public String getStats() {
        dataService.printCacheStats();
        return "Check server logs for cache stats";
    }
}

说明:

  • /get/{key}: 获取缓存数据。
  • /put: 手动存入缓存。
  • /invalidate/{key}: 移除缓存。
  • /stats: 查看缓存统计信息(输出到日志)。

  1. 测试缓存功能

运行 Spring Boot 应用后,可以通过以下方式测试:

  1. 启动应用: 确保 Spring Boot 应用已启动(默认端口 8080)。
  2. 测试接口 : 使用 curl 或 Postman 进行测试:
  3. 验证缓存行为 :
    • 检查缓存是否按配置的过期时间(如 10 分钟)失效。
    • 使用 guavaCache.stats() 查看命中率等信息。

  1. 集成 Spring Cache(可选)

如果希望结合 Spring 的缓存抽象(@Cacheable 等注解),可以创建一个自定义 CacheManager 来使用 Guava Cache。

java

java 复制代码
import com.google.common.cache.CacheBuilder;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class SpringCacheConfig {

    @Bean
    public CacheManager cacheManager() {
        GuavaCacheManager cacheManager = new GuavaCacheManager("myCache");
        cacheManager.setCacheBuilder(
                CacheBuilder.newBuilder()
                        .maximumSize(1000)
                        .expireAfterWrite(10, TimeUnit.MINUTES)
        );
        return cacheManager;
    }
}

然后在 Service 中使用注解:

java

java 复制代码
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class DataService {

    @Cacheable(value = "myCache", key = "#key")
    public String getData(String key) {
        // 模拟从数据库加载
        return "Value for " + key;
    }
}

说明:

  • @Cacheable: 自动缓存方法结果,缓存名为 myCache。
  • Spring Cache 抽象简化了开发,但需要额外配置 CacheManager。

  1. 项目实践中的注意事项

  2. 缓存淘汰策略:

    • 根据业务需求调整 maximumSize 和过期时间。
    • 如果数据量较大,考虑 expireAfterAccess 以避免内存溢出。
  3. 线程安全:

    • Guava Cache 是线程安全的,无需额外同步。
  4. 监控缓存性能:

    • 使用 cache.stats() 监控命中率和加载时间,优化缓存配置。
  5. 异常处理:

    • 在 CacheLoader.load 中处理数据源异常,避免缓存失败影响业务。
  6. 分布式场景的局限:

    • Guava Cache 是本地缓存,数据不共享。如果需要分布式缓存,考虑 Redis 或 J2Cache。
  7. 日志和调试:

    • 开启 Guava 的统计功能,记录缓存命中率、加载时间等,分析性能瓶颈。

  1. 示例项目结构
text 复制代码
src
├── main
│   ├── java
│   │   ├── com.example.demo
│   │   │   ├── config
│   │   │   │   ├── GuavaCacheConfig.java
│   │   │   │   ├── SpringCacheConfig.java (可选)
│   │   │   ├── controller
│   │   │   │   ├── CacheController.java
│   │   │   ├── service
│   │   │   │   ├── DataService.java
│   │   │   ├── DemoApplication.java
│   ├── resources
│   │   ├── application.properties

  1. 扩展:与数据库结合的实践

假设你有一个用户查询场景,需要缓存数据库查询结果:

java

java 复制代码
@Service
public class UserService {

    @Autowired
    private LoadingCache<String, User> userCache;

    @Autowired
    private UserRepository userRepository; // Spring Data JPA

    @Bean
    public LoadingCache<String, User> userCache() {
        return CacheBuilder.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(1, TimeUnit.HOURS)
                .build(new CacheLoader<String, User>() {
                    @Override
                    public User load(String userId) throws Exception {
                        return userRepository.findById(userId)
                                .orElseThrow(() -> new RuntimeException("User not found"));
                    }
                });
    }

    public User getUser(String userId) {
        try {
            return userCache.get(userId);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get user", e);
        }
    }
}

说明:

  • 缓存 User 对象,load 方法从数据库查询。
  • 缓存命中时直接返回,减少数据库访问。

  1. 性能优化建议
  • 调整缓存大小: 根据 JVM 内存和数据规模设置 maximumSize。
  • 异步加载: 使用 CacheBuilder.buildAsync 实现异步加载,提升性能。
  • 监控命中率: 定期检查 cache.stats().hitRate(),优化缓存策略。
  • 避免缓存穿透: 在 load 方法中处理空值(如返回默认值或抛异常)。
相关推荐
夜影风11 小时前
Nginx反向代理与缓存实现
运维·nginx·缓存
编程(变成)小辣鸡13 小时前
Redis 知识点与应用场景
数据库·redis·缓存
菜菜子爱学习1 天前
Nginx学习笔记(八)—— Nginx缓存集成
笔记·学习·nginx·缓存·运维开发
魏波.1 天前
常用缓存软件分类及详解
缓存
yh云想1 天前
《多级缓存架构设计与实现全解析》
缓存·junit
白仑色1 天前
Redis 如何保证数据安全?
数据库·redis·缓存·集群·主从复制·哨兵·redis 管理工具
浩浩测试一下2 天前
02高级语言逻辑结构到汇编语言之逻辑结构转换 if (...) {...} else {...} 结构
汇编·数据结构·数据库·redis·安全·网络安全·缓存
ycchenG72 天前
缓存元数据损坏操作步骤(lvmcache修复)
linux·缓存
2301_793086872 天前
Redis 03 redis 缓存异常
数据库·redis·缓存
hj10433 天前
redis开启局域网访问
数据库·redis·缓存