# Java-缓存-Caffeine

# 使用

依赖:

<!-- spring-boot 已管理该依赖 -->
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>3.2.0</version>
</dependency>

示例:

import com.github.benmanes.caffeine.cache.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletableFuture;

public class CaffeineDemo {

    public static void main(String[] args) {
        basicUsageDemo();
        loadingCacheDemo();
        asyncLoadingCacheDemo();
        evictionDemo();
        statisticsDemo();
    }

    /**
     * 基础缓存操作示例
     */
    public static void basicUsageDemo() {
        System.out.println("\n=== 1. 基础缓存操作 ===");
        
        Cache<String, String> cache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS) // 写入5秒后过期
            .maximumSize(100)                     // 最大100个条目
            .build();

        // 手动写入
        cache.put("key1", "value1");
        
        // 获取值(不存在返回null)
        String value = cache.getIfPresent("key1");
        System.out.println("获取key1: " + value);  // 输出: value1

        // 获取或计算(线程安全)
        String value2 = cache.get("key2", k -> "computed-" + k);
        System.out.println("获取key2: " + value2); // 输出: computed-key2
    }

    /**
     * 自动加载缓存示例
     */
    public static void loadingCacheDemo() {
        System.out.println("\n=== 2. 自动加载缓存 ===");
        
        LoadingCache<String, String> cache = Caffeine.newBuilder()
            .expireAfterAccess(3, TimeUnit.SECONDS) // 3秒未访问则过期
            .maximumSize(10)
            .build(key -> {
                // 模拟从数据库加载
                System.out.println("正在加载: " + key);
                return "db-value-" + key;
            });

        // 自动触发加载函数
        System.out.println(cache.get("user1001")); // 输出: db-value-user1001
        System.out.println(cache.get("user1001")); // 第二次直接从缓存获取
    }

    /**
     * 异步加载缓存示例
     */
    public static void asyncLoadingCacheDemo() {
        System.out.println("\n=== 3. 异步加载缓存 ===");
        
        AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.SECONDS)
            .maximumSize(1000)
            .buildAsync(key -> {
                // 模拟异步加载
                return CompletableFuture.supplyAsync(() -> {
                    System.out.println("异步加载: " + key);
                    return "async-value-" + key;
                });
            });

        // 异步获取
        cache.get("id123").thenAccept(value -> {
            System.out.println("异步获取结果: " + value); // 输出: async-value-id123
        });
    }

    /**
     * 淘汰策略示例
     */
    public static void evictionDemo() {
        System.out.println("\n=== 4. 淘汰策略 ===");
        
        Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(3) // 测试用的小容量
            .removalListener((key, value, cause) -> 
                System.out.printf("淘汰事件: key=%s, 原因=%s\n", key, cause))
            .build();

        cache.put("k1", "v1");
        cache.put("k2", "v2");
        cache.put("k3", "v3");
        cache.put("k4", "v4"); // 触发淘汰(LRU)

        System.out.println("当前大小: " + cache.estimatedSize()); // 输出: 3
    }

    /**
     * 统计功能示例
     */
    public static void statisticsDemo() {
        System.out.println("\n=== 5. 统计功能 ===");
        
        Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(100)
            .recordStats() // 开启统计
            .build();

        cache.put("k1", "v1");
        cache.getIfPresent("k1");
        cache.getIfPresent("missingKey");

        CacheStats stats = cache.stats();
        System.out.println("命中率: " + stats.hitRate());    // 输出: 0.5
        System.out.println("命中数: " + stats.hitCount());    // 输出: 1
        System.out.println("未命中数: " + stats.missCount()); // 输出: 1
    }
}

# 参考

本章目录