Caffeine入门到实战

高性能Java缓存框架实战,让你秒懂缓存优化

前言

在当今高并发的互联网应用中,缓存已经成为提升系统性能的关键技术之一。本文将带你从零开始,深入浅出地学习Caffeine这款高性能的Java缓存框架,并通过实际案例让你掌握缓存技术的精髓。

1. Caffeine简介

Caffeine是一个基于Java的高性能缓存库,由Google开发并开源。它被认为是Java缓存领域的王者,在性能测试中表现优异。

为什么选择Caffeine?

  • 高性能:采用先进的算法,读写性能卓越
  • 功能丰富:支持多种过期策略、异步加载、统计信息等
  • 线程安全:并发性能优秀
  • 易于使用:API设计简洁直观
  • 活跃社区:持续维护和更新

架构设计

Caffeine的核心架构包括:

  1. 缓存容器:使用ConcurrentHashMap作为底层数据结构
  2. 访问策略:采用Window TinyLFU算法进行频率统计
  3. 淘汰策略:基于时间窗口和频率的混合淘汰策略
  4. 事件机制:支持监听缓存的各种事件

2. 快速入门

Maven依赖

复制代码
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version>
</dependency>

基础使用示例

复制代码
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;

public class BasicCacheExample {
    public static void main(String[] args) {
        // 创建缓存
        Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(1000) // 最大缓存数量
            .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
            .build();

        // 存储数据
        cache.put("key1", "value1");

        // 获取数据
        String value = cache.getIfPresent("key1");
        System.out.println("缓存值: " + value);

        // 获取或计算
        String value2 = cache.get("key2", k -> "defaultValue");
        System.out.println("缓存值: " + value2);

        // 移除数据
        cache.invalidate("key1");
    }
}

3. 核心概念

3.1 Cache vs LoadingCache vs AsyncLoadingCache

Caffeine提供了三种缓存类型:

  1. Cache:基础缓存,需要手动管理数据
  2. LoadingCache:自动加载数据的缓存
  3. AsyncLoadingCache:异步加载数据的缓存

3.2 过期策略

Caffeine提供了三种过期策略:

复制代码
Caffeine.newBuilder()
    .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后过期
    .expireAfterAccess(5, TimeUnit.MINUTES)  // 最后访问后过期
    .expireAfter(30, TimeUnit.MINUTES);       // 自定义过期逻辑

3.3 淘汰策略

复制代码
Caffeine.newBuilder()
    .maximumSize(1000)         // 基于数量
    .maximumWeight(10000)      // 基于权重
    .weakKeys()               // 弱引用键
    .weakValues()             // 弱引用值
    .softValues();            // 软引用值

4. 高级特性

4.1 异步加载

复制代码
AsyncLoadingCache<String, User> asyncCache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .buildAsync(key -> loadUserFromDatabase(key));

// 异步获取
CompletableFuture<User> userFuture = asyncCache.get("user1");
userFuture.thenAccept(user -> {
    System.out.println("获取用户: " + user.getName());
});

4.2 事件监听

复制代码
Cache<String, String> cache = Caffeine.newBuilder()
    .maximumSize(1000)
    .removalListener((key, value, cause) -> {
        System.out.println("缓存移除: " + key + " -> " + value + ", 原因: " + cause);
    })
    .build();

4.3 统计信息

复制代码
Cache<String, String> cache = Caffeine.newBuilder()
    .maximumSize(1000)
    .recordStats() // 启用统计
    .build();

// 使用缓存...
cache.put("key1", "value1");
cache.getIfPresent("key1");

// 获取统计信息
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());
System.out.println("加载时间: " + stats.averageLoadPenalty());
System.out.println("请求数: " + stats.requestCount());

5. Spring Boot集成

5.1 添加依赖

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

5.2 配置类

复制代码
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 {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeineCacheBuilder());
        return cacheManager;
    }

    private Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(1000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .recordStats();
    }
}

5.3 使用注解

复制代码
package com.example.caffeine.demo.service;

import com.example.caffeine.demo.model.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {

    // 模拟数据库存储
    private final Map<Long, User> userMap = new ConcurrentHashMap<>();

    public UserService() {
        // 初始化一些测试数据
        userMap.put(1L, new User(1L, "张三", "zhangsan@example.com", "13800138000"));
        userMap.put(2L, new User(2L, "李四", "lisi@example.com", "13900139000"));
        userMap.put(3L, new User(3L, "王五", "wangwu@example.com", "13700137000"));
    }

    /**
     * 获取用户信息(带缓存)
     * @param userId 用户ID
     * @return 用户信息
     */
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(Long userId) {
        // 模拟数据库查询耗时
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        User user = userMap.get(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + userId);
        }
        return user;
    }

    /**
     * 获取用户信息(异步)
     */
    public CompletableFuture<User> getUserByIdAsync(Long userId) {
        return CompletableFuture.supplyAsync(() -> getUserById(userId));
    }

    /**
     * 获取所有用户信息
     */
    @Cacheable(value = "users", key = "'all'")
    public List<User> getAllUsers() {
        // 模拟数据库查询耗时
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        return new ArrayList<>(userMap.values());
    }

    /**
     * 创建用户
     */
    @CachePut(value = "users", key = "#user.id")
    public User createUser(User user) {
        userMap.put(user.getId(), user);
        return user;
    }

    /**
     * 更新用户信息
     */
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        if (!userMap.containsKey(user.getId())) {
            throw new RuntimeException("用户不存在: " + user.getId());
        }
        user.setUpdateTime(LocalDateTime.now());
        userMap.put(user.getId(), user);
        return user;
    }

    /**
     * 删除用户
     */
    @CacheEvict(value = "users", key = "#userId")
    public void deleteUser(Long userId) {
        User removed = userMap.remove(userId);
        if (removed == null) {
            throw new RuntimeException("用户不存在: " + userId);
        }
    }

    /**
     * 批量获取用户信息
     */
    @Cacheable(value = "users", key = "'batch:' + #userIds.hashCode()")
    public Map<Long, User> batchGetUsers(Set<Long> userIds) {
        // 模拟批量查询耗时
        try {
            TimeUnit.MILLISECONDS.sleep(150);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        Map<Long, User> result = new HashMap<>();
        for (Long userId : userIds) {
            User user = userMap.get(userId);
            if (user != null) {
                result.put(userId, user);
            }
        }
        return result;
    }

    /**
     * 根据用户名模糊查询
     */
    public List<User> searchUsersByUsername(String keyword) {
        List<User> result = new ArrayList<>();
        for (User user : userMap.values()) {
            if (user.getUsername().contains(keyword)) {
                result.add(user);
            }
        }
        return result;
    }

    /**
     * 清空所有缓存
     */
    @CacheEvict(value = "users", allEntries = true)
    public void clearAllCache() {
        System.out.println("清空所有用户缓存");
    }

    /**
     * 获取用户总数
     */
    public long getUserCount() {
        return userMap.size();
    }
}

6. 生产环境最佳实践

6.1 缓存雪崩与击穿

缓存雪崩解决方案
复制代码
// 1. 设置随机过期时间
Caffeine.newBuilder()
    .expireAfterWrite(10 + new Random().nextInt(5), TimeUnit.MINUTES);

// 2. 使用互斥锁
private final Lock lock = new ReentrantLock();

public User getUserWithLock(Long id) {
    User user = cache.getIfPresent(id);
    if (user != null) {
        return user;
    }

    lock.lock();
    try {
        // 双重检查
        user = cache.getIfPresent(id);
        if (user != null) {
            return user;
        }

        user = userRepository.findById(id);
        cache.put(id, user);
        return user;
    } finally {
        lock.unlock();
    }
}
缓存击穿解决方案
复制代码
// 使用Caffeine的异步加载
AsyncLoadingCache<Long, User> asyncCache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .buildAsync(key -> loadUserFromDatabase(key));

public User getUser(Long id) {
    return asyncCache.get(id).join();
}

6.2 缓存预热

复制代码
package com.example.caffeine.demo.cache;

import com.example.caffeine.demo.model.User;
import com.example.caffeine.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 缓存预热启动器
 *
 * 功能:
 * 1. 在应用启动时自动预热热点数据到缓存
 * 2. 支持同步和异步预热方式
 * 3. 支持批量预热
 * 4. 提供预热进度监控
 * 5. 异常处理和重试机制
 */
@Slf4j
@Component
public class CacheWarmupRunner implements CommandLineRunner {

    @Autowired
    private UserService userService;

    /**
     * 预热配置
     */
    private static class WarmupConfig {
        // 预热用户ID列表(可以根据业务需求配置)
        private static final List<Long> HOT_USER_IDS = Arrays.asList(1L, 2L, 3L, 4L, 5L);

        // 预热批次大小
        private static final int BATCH_SIZE = 3;

        // 线程池大小
        private static final int THREAD_POOL_SIZE = 2;

        // 是否启用异步预热
        private static final boolean ASYNC_WARMUP = true;

        // 最大重试次数
        private static final int MAX_RETRY_TIMES = 3;

        // 重试间隔(毫秒)
        private static final long RETRY_INTERVAL = 1000L;
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("开始执行缓存预热...");
        long startTime = System.currentTimeMillis();

        try {
            if (WarmupConfig.ASYNC_WARMUP) {
                // 异步预热
                asyncWarmup();
            } else {
                // 同步预热
                syncWarmup();
            }

            long endTime = System.currentTimeMillis();
            log.info("缓存预热完成!耗时: {} ms", endTime - startTime);

        } catch (Exception e) {
            log.error("缓存预热失败!错误信息: {}", e.getMessage(), e);
        }
    }

    /**
     * 同步预热方式
     */
    private void syncWarmup() {
        log.info("使用同步方式预热缓存...");

        // 方法1:逐个预热
        log.info("逐个预热用户数据...");
        for (Long userId : WarmupConfig.HOT_USER_IDS) {
            warmupSingleUser(userId);
        }

        // 方法2:批量预热
        log.info("批量预热用户数据...");
        batchWarmupUsers(WarmupConfig.HOT_USER_IDS);

        // 方法3:预热所有用户
        log.info("预热所有用户数据...");
        warmupAllUsers();
    }

    /**
     * 异步预热方式
     */
    private void asyncWarmup() {
        log.info("使用异步方式预热缓存...");

        ExecutorService executor = Executors.newFixedThreadPool(WarmupConfig.THREAD_POOL_SIZE);

        // 创建异步预热任务
        List<CompletableFuture<Void>> futures = WarmupConfig.HOT_USER_IDS.stream()
            .map(userId -> CompletableFuture.runAsync(() -> {
                try {
                    warmupSingleUserWithRetry(userId);
                } catch (Exception e) {
                    log.error("预热用户 {} 失败: {}", userId, e.getMessage());
                }
            }, executor))
            .collect(Collectors.toList());

        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .whenComplete((result, ex) -> {
                if (ex != null) {
                    log.error("部分预热任务失败", ex);
                } else {
                    log.info("所有预热任务完成");
                }
                executor.shutdown();
            })
            .join();
    }

    /**
     * 预热单个用户数据(带重试机制)
     */
    private void warmupSingleUserWithRetry(Long userId) {
        int retryCount = 0;
        boolean success = false;

        while (retryCount < WarmupConfig.MAX_RETRY_TIMES && !success) {
            try {
                warmupSingleUser(userId);
                success = true;
                log.debug("用户 {} 预热成功,尝试次数: {}", userId, retryCount + 1);
            } catch (Exception e) {
                retryCount++;
                if (retryCount >= WarmupConfig.MAX_RETRY_TIMES) {
                    log.error("用户 {} 预热失败,已达到最大重试次数: {}", userId, e.getMessage());
                    throw new RuntimeException("预热用户 " + userId + " 失败", e);
                }
                log.warn("用户 {} 预热失败,第{}次重试。错误: {}", userId, retryCount, e.getMessage());
                try {
                    Thread.sleep(WarmupConfig.RETRY_INTERVAL);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("预热被中断", ie);
                }
            }
        }
    }

    /**
     * 预热单个用户
     */
    private void warmupSingleUser(Long userId) {
        log.info("预热用户: {}", userId);
        try {
            // 预热用户基本信息
            User user = userService.getUserById(userId);
            log.debug("用户 {} 基本信息预热完成", userId);
            // 预热相关数据(如果有)
            warmupRelatedData(user);

        } catch (Exception e) {
            log.error("预热用户 {} 失败: {}", userId, e.getMessage());
            throw e;
        }
    }

    /**
     * 批量预热用户数据
     */
    private void batchWarmupUsers(List<Long> userIds) {
        log.info("批量预热用户: {}", userIds);

        // 按批次处理
        for (int i = 0; i < userIds.size(); i += WarmupConfig.BATCH_SIZE) {
            int end = Math.min(i + WarmupConfig.BATCH_SIZE, userIds.size());
            List<Long> batch = userIds.subList(i, end);

            log.info("预热第 {} 批,用户ID: {}", (i / WarmupConfig.BATCH_SIZE) + 1, batch);

            try {
                // 批量查询
                Map<Long, User> users = userService.batchGetUsers(new HashSet<>(batch));
                log.info("批量预热完成,成功预热 {} 个用户", users.size());

                // 添加批次间间隔,避免压力过大
                if (end < userIds.size()) {
                    Thread.sleep(500);
                }

            } catch (Exception e) {
                log.error("批量预热失败: {}", e.getMessage());
                // 单个预热降级
                for (Long userId : batch) {
                    try {
                        warmupSingleUser(userId);
                    } catch (Exception ex) {
                        log.error("降级预热用户 {} 失败: {}", userId, ex.getMessage());
                    }
                }
            }
        }
    }

    /**
     * 预热所有用户
     */
    private void warmupAllUsers() {
        log.info("开始预热所有用户数据...");
        try {
            List<User> allUsers = userService.getAllUsers();
            log.info("预热所有用户完成,共 {} 个用户", allUsers.size());
            // 预热用户的其他关联数据
            for (User user : allUsers) {
                warmupRelatedData(user);
                // 添加间隔,避免一次性加载过多数据
                Thread.sleep(100);
            }
        } catch (Exception e) {
            log.error("预热所有用户失败: {}", e.getMessage());
            throw e;
        }
    }

    /**
     * 预热相关数据
     */
    private void warmupRelatedData(User user) {
        // 预热用户的行为数据
        warmupUserActivities(user.getId());
    }

    /**
     * 预热用户行为数据
     */
    private void warmupUserActivities(Long userId) {
        try {
            // 调用行为服务预热
            // activityService.warmupUserActivities(userId);
            log.debug("预热用户 {} 的行为数据", userId);
        } catch (Exception e) {
            log.warn("预热用户 {} 的行为数据失败: {}", userId, e.getMessage());
        }
    }


    /**
     * 验证预热结果
     */
    public void verifyWarmupResult() {
        log.info("验证预热结果...");
        int successCount = 0;
        int totalCount = WarmupConfig.HOT_USER_IDS.size();
        for (Long userId : WarmupConfig.HOT_USER_IDS) {
            try {
                // 测试缓存是否命中
                long startTime = System.nanoTime();
                User user = userService.getUserById(userId);
                long endTime = System.nanoTime();
                long duration = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
                if (duration < 10) { // 如果响应时间小于10ms,说明命中了缓存
                    successCount++;
                    log.debug("用户 {} 缓存预热验证成功,响应时间: {} ms", userId, duration);
                } else {
                    log.warn("用户 {} 缓存预热验证失败,响应时间: {} ms", userId, duration);
                }
            } catch (Exception e) {
                log.error("验证用户 {} 失败: {}", userId, e.getMessage());
            }
        }
        log.info("预热结果验证完成,成功率: {} / {} ({:.2f}%)",
                successCount, totalCount, (double) successCount / totalCount * 100);
    }
}

6.3 缓存监控

复制代码
 @Autowired
    private CacheManager cacheManager;
    // 预警阈值配置
    private static class AlertThreshold {
        // 命中率阈值(低于此值发出警告)
        private static final double MIN_HIT_RATE = 0.8;
        // 平均加载时间阈值(超过此值发出警告)
        private static final long MAX_AVG_LOAD_TIME_MS = 100;
        // 内存使用率阈值
        private static final double MAX_MEMORY_USAGE_PERCENT = 80.0;
        // 错误率阈值
        private static final double MAX_ERROR_RATE = 0.01;
        // 缓存大小阈值
        private static final long MAX_CACHE_SIZE = 10000;
    }

    /**
     * 获取所有缓存的统计信息
     */
    @GetMapping("/stats")
    public ResponseEntity<Map<String, Object>> getAllCacheStats() {
        Map<String, Object> result = new LinkedHashMap<>();
        // 获取所有缓存名称
        List<String> cacheNames = cacheManager.getCacheNames();
        result.put("timestamp", LocalDateTime.now());
        result.put("cacheNames", cacheNames);
        result.put("cacheCount", cacheNames.size());
        // 统计汇总
        CacheSummary summary = new CacheSummary();
        for (String cacheName : cacheNames) {
            try {
                Map<String, Object> cacheStat = getCacheStat(cacheName);
                result.put(cacheName, cacheStat);
                // 汇总统计
                summary.aggregate(cacheStat);
            } catch (Exception e) {
                log.error("获取缓存 {} 的统计信息失败: {}", cacheName, e.getMessage());
                result.put(cacheName, "获取统计信息失败: " + e.getMessage());
            }
        }
        result.put("summary", summary);
        result.put("health", getCacheHealthStatus(summary));
        return ResponseEntity.ok(result);
    }

    /**
     * 获取指定缓存的统计信息
     */
    @GetMapping("/stats/{cacheName}")
    public ResponseEntity<Map<String, Object>> getCacheStat(@PathVariable String cacheName) {
        log.info("获取缓存 {} 的统计信息", cacheName);
        Map<String, Object> result = new HashMap<>();
        try {
            org.springframework.cache.Cache springCache = cacheManager.getCache(cacheName);
            if (springCache == null) {
                return ResponseEntity.notFound().build();
            }
            Object nativeCache = springCache.getNativeCache();
            if (nativeCache instanceof Cache) {
                Cache<?, ?> cache = (Cache<?, ?>) nativeCache;
                CacheStats stats = cache.stats();
                // 基本信息
                result.put("name", cacheName);
                result.put("size", estimateCacheSize(cache));
                result.put("estimatedMemoryUsage", estimateMemoryUsage(cache));
                // 统计数据
                result.put("requestCount", stats.requestCount());
                result.put("hitCount", stats.hitCount());
                result.put("missCount", stats.missCount());
                result.put("hitRate", stats.hitRate());
                result.put("missRate", stats.missRate());
                // 加载统计
                result.put("loadSuccessCount", stats.loadSuccessCount());
                result.put("loadFailureCount", stats.loadFailureCount());
                result.put("loadFailureRate", calculateLoadFailureRate(stats));
                result.put("totalLoadTime", stats.totalLoadTime());
                result.put("averageLoadPenalty", stats.averageLoadPenalty());
                // 淘汰统计
                result.put("evictionCount", stats.evictionCount());
                result.put("evictionWeight", stats.evictionWeight());
                // 其他统计
                result.put("rejectionCount", stats.rejectionCount());
                // 计算衍生指标
                result.put("errorRate", calculateErrorRate(stats));
                result.put("loadSuccessRate", calculateLoadSuccessRate(stats));
                // 预警信息
                result.put("alerts", checkCacheAlerts(cacheName, stats, cache.estimatedSize()));
            } else {
                result.put("error", "不支持的缓存类型: " + nativeCache.getClass().getName());
            }
        } catch (Exception e) {
            log.error("获取缓存 {} 统计信息失败: {}", cacheName, e.getMessage());
            result.put("error", e.getMessage());
        }
        result.put("timestamp", LocalDateTime.now());
        return ResponseEntity.ok(result);
    }

7. 性能优化技巧

7.1 批量加载优化

复制代码
// 批量加载优化
public class BatchUserService {

    private final AsyncLoadingCache<Long, User> userCache;

    public BatchUserService() {
        this.userCache = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .buildAsync(this::batchLoadUsers);
    }

    private Map<Long, User> batchLoadUsers(Set<Long> userIds) {
        if (userIds.isEmpty()) {
            return Collections.emptyMap();
        }

        // 批量查询数据库
        List<User> users = userRepository.findAllById(userIds);

        // 转换为Map
        return users.stream()
            .collect(Collectors.toMap(User::getId, user -> user));
    }

    public Map<Long, User> getUsers(Set<Long> userIds) {
        return userCache.getAll(userIds).join();
    }
}

8. 实战案例

8.1 用户信息缓存服务

复制代码
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class UserInfoCacheService {

    private final Cache<Long, UserInfo> userInfoCache;

    public UserInfoCacheService() {
        this.userInfoCache = Caffeine.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(30, TimeUnit.MINUTES)
            .expireAfterAccess(10, TimeUnit.MINUTES)
            .recordStats()
            .build();
    }

    /**
     * 获取用户信息
     */
    public UserInfo getUserInfo(Long userId) {
        return userInfoCache.get(userId, this::loadUserInfoFromDB);
    }

    /**
     * 批量获取用户信息
     */
    public Map<Long, UserInfo> batchGetUserInfo(Set<Long> userIds) {
        return userInfoCache.getAll(userIds, this::batchLoadUserInfoFromDB);
    }

    /**
     * 更新用户信息
     */
    public void updateUserInfo(Long userId, UserInfo userInfo) {
        userInfoCache.put(userId, userInfo);
    }

    /**
     * 删除用户信息
     */
    public void removeUserInfo(Long userId) {
        userInfoCache.invalidate(userId);
    }

    /**
     * 获取缓存统计
     */
    public CacheStats getCacheStats() {
        return userInfoCache.stats();
    }

    /**
     * 从数据库加载用户信息
     */
    private UserInfo loadUserInfoFromDB(Long userId) {
        // 模拟数据库查询
        try {
            Thread.sleep(100); // 模拟数据库查询耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return userRepository.findById(userId);
    }

    /**
     * 批量从数据库加载用户信息
     */
    private Map<Long, UserInfo> batchLoadUserInfoFromDB(Set<Long> userIds) {
        return userRepository.findAllById(userIds).stream()
            .collect(Collectors.toMap(UserInfo::getId, Function.identity()));
    }
}

9. 总结

Caffeine作为Java缓存领域的佼佼者,凭借其出色的性能和丰富的功能,已经成为许多项目的首选缓存方案。

相关推荐
砚边数影1 小时前
AI开发依赖引入:DL4J / Java-ML 框架 Maven 坐标配置
java·数据库·人工智能·深度学习·机器学习·ai·maven
一路向北North1 小时前
nacos更改配置值后,应用提示Refresh keys changed 但是注入的值没有发生变化
java
黎雁·泠崖2 小时前
Java面向对象:this关键字+构造方法+标准JavaBean
java·开发语言·python
sheji34162 小时前
【开题答辩全过程】以 基于Java的智慧环卫垃圾收运管理系统设计与实现为例,包含答辩的问题和答案
java·开发语言
jason成都2 小时前
实战 | 国产数据库 R2DBC-JDBC 桥接踩坑记 - JetLinks适配达梦数据库
java·数据库·物联网
BullSmall3 小时前
SEDA (Staged Event-Driven Architecture, 分阶段事件驱动架构
java·spring·架构
Coder_Boy_3 小时前
基于SpringAI的在线考试系统-DDD(领域驱动设计)核心概念及落地架构全总结(含事件驱动协同逻辑)
java·人工智能·spring boot·微服务·架构·事件驱动·领域驱动
黎雁·泠崖3 小时前
Java&C语法对比:分支与循环结构核心全解析
java·c语言
鹿角片ljp3 小时前
Java IO流案例:使用缓冲流恢复《出师表》文章顺序
java·开发语言·windows