Spring Boot Cache 增加过期时间验证

核心实现思想

利用Java继承的特性,覆盖Spring默认获取缓存的方法,增加有效期验证。

实现步骤

步骤1:继承 Spring 默认缓存管理器ConcurrentMapManage

@Component
@EnableCaching
public class ConcurrentTokenCacheManager extends ConcurrentMapCacheManager {
    private SerializationDelegate serialization;

    @PostConstruct
    public void initSerialization() {
        Field serialization = ReflectionUtils.findField(ConcurrentMapCacheManager.class, "serialization");
        ReflectionUtils.makeAccessible(serialization);
        this.serialization = (SerializationDelegate) ReflectionUtils.getField(serialization, this);
    }

    @Override
    protected Cache createConcurrentMapCache(String name) {
        SerializationDelegate actualSerialization = this.isStoreByValue() ? this.serialization : null;
        return new ConcurrentTokenCache(name, new ConcurrentHashMap(256), this.isAllowNullValues(), actualSerialization);
    }
}

1、利用@PostConstruct实现Bean初始化后调用特性,通过反射拿到ConcurrentMapCacheManager初始化的SerializationDelegate序列化对象。(由于ConcurrentMapCacheManager未提供SerializationDelegate的访问权限,所以此处利用反射机制修复属性访问权限,核心代码:ReflectionUtils.makeAccessible(serialization);

2、覆盖缓存管理器方法 createConcurrentMapCache实现自定义Cache。

步骤2:继承Spring默认缓存实现ConcurrentMapCache

public class ConcurrentTokenCache extends ConcurrentMapCache {

    public ConcurrentTokenCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues, @Nullable SerializationDelegate serialization) {
        super(name, store, allowNullValues, serialization);
    }

    @Override
    protected Object lookup(Object key) {
        Object lookup = super.lookup(key);
        if (lookup instanceof CacheToken && ((CacheToken) lookup).isExpiration()) {
            log.info("Token is Expiration !");
            super.evict(key);
            return null;
        }
        return lookup;
    }

    @Override
    public void put(Object key, Object value) {
        log.info("Put Cache {} = {}", key, value);
        super.put(key, value);
    }
}
public abstract class CacheToken {
    private String token;
    private Date expirationTime;

    /**
     * 校验是否失效
     * @return true 已失效 | false 未失效
     */
    public boolean isExpiration() {
        return expirationTime.before(new Date());
    }
}

 覆盖ConcurrentMapCache.lookup方法,此处实现Token的有效期验证。其中CacheToken为自定义抽象对象,由缓存业务对象继承。

覆盖ConcurrentMapCache.put方法,由于缓存属于被动失效模式,即获取时才验证缓存是否过期,如果系统中缓存数据太多会对本地内存造成不必要的浪费,因此可以通过覆盖put方法增加定时任务机制,定时清理过期缓存,达到性能上优化。

实战测试

@Cacheable(cacheManager = "concurrentTokenCacheManager", cacheNames = "CompanyToken", key = "#businessId")
public MallToken getCompanyToken(String businessId, String clientId, String clientSecret) {
    log.info("创建Token");
    MallToken token = new MallToken();
    token.setToken("xxxxx");
    LocalDateTime dateTime = LocalDateTime.now().plusSeconds(10);
    token.setExpirationTime(Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()));
    return token;
}

PS: cacheNames 必填,否则会报错。cacheManager 可以不用设置,当系统有多个缓存管理器时最好指定一个管理器。 


文章知识点总结 

继承:子类可访问父类非私有的属性和方法。

反射:通过Java反射机制修改对象私有属性或方法的访问权限,获取或设置对象私有属性或方法。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值