Java缓存过期案例如何设置清除

wen java案例 26

本文目录导读:

Java缓存过期案例如何设置清除

  1. 使用 Guava Cache(最常用)
  2. 使用 Caffeine(性能更好,Guava的继承者)
  3. 使用 Redis(分布式场景)
  4. 手动实现简单缓存(带过期清除)
  5. 使用 Spring Cache(企业级应用)
  6. 缓存过期清除的最佳实践
  7. 选择建议

在Java缓存中设置过期清除,主要有以下几种常见方案,从简单到复杂:

使用 Guava Cache(最常用)

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.Cache;
import java.util.concurrent.TimeUnit;
public class GuavaCacheExample {
    public static void main(String[] args) {
        // 创建缓存,设置过期策略
        Cache<String, Object> cache = CacheBuilder.newBuilder()
            // 写入后固定时间过期
            .expireAfterWrite(10, TimeUnit.MINUTES)
            // 或:访问后固定时间过期(如果一直在访问,就不会过期)
            // .expireAfterAccess(30, TimeUnit.MINUTES)
            // 最大缓存数量
            .maximumSize(1000)
            .build();
        // 放入缓存
        cache.put("key1", "value1");
        // 获取缓存
        Object value = cache.getIfPresent("key1");
        System.out.println(value);
    }
}

使用 Caffeine(性能更好,Guava的继承者)

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;
public class CaffeineCacheExample {
    public static void main(String[] args) {
        Cache<String, Object> cache = Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)  // 写入后10分钟过期
            .expireAfterAccess(30, TimeUnit.MINUTES) // 访问后30分钟过期
            .maximumSize(10000)                       // 最大条目数
            .build();
        cache.put("user_123", "user_data");
        Object data = cache.getIfPresent("user_123");
        System.out.println(data);
    }
}

使用 Redis(分布式场景)

import redis.clients.jedis.Jedis;
public class RedisCacheExample {
    private static final Jedis jedis = new Jedis("localhost", 6379);
    // 设置带过期时间的缓存
    public static void setWithExpire(String key, String value, int seconds) {
        jedis.setex(key, seconds, value); // 设置值并指定过期时间(秒)
    }
    // 或使用更精确的过期时间
    public static void setWithExpireAt(String key, String value, long unixTime) {
        jedis.set(key, value);
        jedis.expireAt(key, unixTime); // 指定具体过期时间戳
    }
    public static void main(String[] args) {
        // 缓存用户信息,10分钟后过期
        setWithExpire("user:123", "{\"name\":\"张三\"}", 600);
        // 或:指定具体过期时间(今晚24点过期)
        long midnight = System.currentTimeMillis() / 1000 + 86400;
        setWithExpireAt("daily_data", "some_value", midnight);
    }
}

手动实现简单缓存(带过期清除)

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class SimpleCache<K, V> {
    private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
    private static class CacheEntry<V> {
        V value;
        long expireTime;
        CacheEntry(V value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }
    }
    // 放入缓存,指定过期时间
    public void put(K key, V value, long duration, TimeUnit unit) {
        long expireTime = System.currentTimeMillis() + unit.toMillis(duration);
        cache.put(key, new CacheEntry<>(value, expireTime));
    }
    // 获取缓存,自动检查是否过期
    public V get(K key) {
        CacheEntry<V> entry = cache.get(key);
        if (entry == null) {
            return null;
        }
        // 检查是否过期
        if (System.currentTimeMillis() > entry.expireTime) {
            cache.remove(key); // 清除过期缓存
            return null;
        }
        return entry.value;
    }
    // 定期清理过期缓存(可选)
    public void cleanExpired() {
        long now = System.currentTimeMillis();
        cache.entrySet().removeIf(entry -> now > entry.getValue().expireTime);
    }
    public static void main(String[] args) throws InterruptedException {
        SimpleCache<String, String> cache = new SimpleCache<>();
        // 设置缓存,5秒过期
        cache.put("key1", "value1", 5, TimeUnit.SECONDS);
        System.out.println(cache.get("key1")); // 输出: value1
        Thread.sleep(6000); // 等待6秒
        System.out.println(cache.get("key1")); // 输出: null(已过期清除)
    }
}

使用 Spring Cache(企业级应用)

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    // 缓存结果,根据配置自动过期
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(String userId) {
        // 模拟数据库查询
        return new User(userId, "张三");
    }
    // 更新缓存,同时设置过期时间(通过配置)
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        // 更新数据库
        return user;
    }
    // 主动清除缓存
    @CacheEvict(value = "users", key = "#userId")
    public void deleteUser(String userId) {
        // 删除用户
    }
}

配置文件(application.yml):

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=500,expireAfterWrite=10m

缓存过期清除的最佳实践

import com.github.benmanes.caffeine.cache.*;
import java.util.concurrent.TimeUnit;
public class CacheBestPractice {
    // 1. 组合过期策略
    public static Cache<String, Object> createStrategicCache() {
        return Caffeine.newBuilder()
            .expireAfter(new Expiry<String, Object>() {
                @Override
                public long expireAfterCreate(String key, Object value, long currentTime) {
                    // 不同key设置不同过期时间
                    if (key.startsWith("session_")) {
                        return TimeUnit.MINUTES.toNanos(30); // session30分钟
                    } else if (key.startsWith("temp_")) {
                        return TimeUnit.SECONDS.toNanos(10);  // 临时数据10秒
                    }
                    return TimeUnit.MINUTES.toNanos(10);      // 默认10分钟
                }
                @Override
                public long expireAfterUpdate(String key, Object value, 
                    long currentTime, long currentDuration) {
                    return currentDuration; // 更新时不改变过期时间
                }
                @Override
                public long expireAfterRead(String key, Object value,
                    long currentTime, long currentDuration) {
                    return currentDuration; // 读取时不改变
                }
            })
            .maximumSize(10000)
            .build();
    }
    // 2. 监听过期事件(清理资源)
    public static void main(String[] args) {
        Cache<String, Object> cache = Caffeine.newBuilder()
            .expireAfterWrite(1, TimeUnit.MINUTES)
            .removalListener((key, value, cause) -> {
                System.out.println("缓存被清除: " + key + 
                    ", 原因: " + cause);
                // 如果有需要释放的资源,在这里处理
                if (value instanceof AutoCloseable) {
                    try {
                        ((AutoCloseable) value).close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            })
            .build();
        cache.put("temp_file", new TempFile("data.txt"));
        // 1分钟后,缓存自动过期,触发移除监听器
    }
    static class TempFile implements AutoCloseable {
        String filename;
        TempFile(String filename) { this.filename = filename; }
        @Override
        public void close() { System.out.println("关闭文件: " + filename); }
    }
}

选择建议

场景 推荐方案 原因
单机应用 Caffeine 性能最好,功能完善
分布式系统 Redis 统一缓存管理
Spring项目 Spring Cache + Caffeine 注解简洁,易于维护
学习/教学 Guava Cache API经典,文档丰富

使用缓存过期时要注意:

  1. 合理设置过期时间,不要太长(占用内存)也不要太短(失去缓存意义)
  2. 考虑缓存穿透问题,使用布隆过滤器等方案
  3. 敏感数据要设置较短过期时间
  4. 监控缓存命中率,及时调整过期策略

抱歉,评论功能暂时关闭!