一次扩展SpringCache的@Cacheable注解的尝试(以Redis为例)

Springcache中为Redis缓存设置个性化过期时间的实现,
本文介绍了如何在Springcache中为单个或一组Redis缓存设置自定义过期时间,包括在YML配置文件中的配置和通过修改@Cacheable注解添加cacheTime属性的方法。

简介

如果需要在Springcache中,为单个或一组redis缓存单独设置过期时间,可以在yml配置文件中如下编写:

spring:
  cache:
    cache-names: caches
    redis:
      # 全局缓存过期时间
      time-to-live: 10m
    # 自定义单个缓存name过期时间
    time-to-live:
      # 单个name过期时间
      cache1: 10m
      # 多个name过期时间,key包含特殊符号需要"[]"包裹
      "[cache1,cache2]": 10m

那么,我们可以扩展@Cacheable注解,直接在注解属性上设置过期时间吗?

方案详情—修改源码

步骤

  1. 在@Cacheable注解中添加cacheTime属性
package org.springframework.cache.annotation;
@Target({
   
   ElementType.TYPE, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Inherited  
@Documented  
@Reflective  
public @interface Cacheable {
   
     
   // ...
  
   // @Modified  
   /**  
    * 过期时间  
    * @return  
    */  
   String cacheTime() default "";
  1. CacheableOperation类中添加cacheTime属性
package org.springframework.cache.interceptor;  
  
import org.springframework.lang.Nullable;  
  
/**  
 * Class describing a cache 'cacheable' operation. * * @author Costin Leau  
 * @author Phillip Webb  
 * @author Marcin Kamionowski  
 * @since 3.1  
 */public class CacheableOperation extends CacheOperation {
   
     
  
   // ...其他属性...
  
   // @Modified1
   @Nullable  
   private final String cacheTime;  
  
   // @Modified2 修改构造
   /**  
    * Create a new {@link CacheableOperation} instance from the given builder.  
    * @since 4.3  
    */   public CacheableOperation(CacheableOperation.Builder b) {
   
     
      super(b);  
      this.unless = b.unless;  
      this.sync = b.sync;  
      // @Modified  
      this.cacheTime = b.cacheTime;  
   }  
  
   // ...其他get方法...
  
   // @Modified3
   public String getCacheTime(){
   
   return this.cacheTime;}  
  
   // @Modified4 修改Builder
   /**  
    * A builder that can be used to create a {@link CacheableOperation}.  
    * @since 4.3  
    */   public static class Builder extends CacheOperation.Builder {
   
     
  
      // ...其他属性和setter...

	  // @Modified
      private String cacheTime;   
  
      // @Modified  
    
<think>好的,我需要回答用户关于Spring Cache中@Cacheable注解处理List类型数据时在Redis中的存储方式的问题。首先,我需要回忆Spring Cache和Redis集成的相关知识,特别是序列化和存储结构部分。 根据用户提供的引用内容,引用[1]和引用[2]提到了使用@Cacheable和@CachePut注解时指定value和key的情况。如,value是缓存名称,key用于生成缓存的键。当存储List类型时,可能会因为序列化方式的不同而导致存储结构变化,比如从List集合变为单个对象,这可能和序列化方式有关。 接下来,引用[3]提到Spring Cache默认不支持在注解中设置过期时间,但可以通过配置RedisCacheManager来统一设置。这说明存储配置可能影响数据在Redis中的结构。 我需要确定当使用@Cacheable存储List时,Redis中是如何保存的。通常,Spring Data Redis默认使用JDK序列化,将整个对象序列化为字节流存储。这可能意味着List会被序列化为一个二进制值,作为字符串类型存储在Redis中,对应的key是生成的缓存键。但有时候,如果配置了不同的序列化方式,比如JSON序列化,存储结构可能会有所不同,比如Hash类型或其他结构。 另外,用户提到在引用[2]中,保存方法导致存储类型从List变为对象,这可能是因为方法返回的是单个对象而不是List,或者序列化方式导致的结构变化。需要解释这种情况的可能原因。 最后,我需要总结存储方式的关键点:缓存键的生成规则、序列化方式的影响以及可能的存储结构(如String或Hash)。同时,需要指出常见问题和解决方案,如配置正确的序列化器来处理集合类型。</think>关于Spring Cache中@Cacheable注解对List类型数据的Redis存储方式,以下是关键点解析: ### 1. 缓存键生成规则 - **value属性**:定义缓存名称,如`"product:seckill"`,作为Redis键名前缀[^1] - **key属性**:定义键名后缀,如`key="'list'"`,最终生成完整键名`product:seckill::list`[^1] - 未指定key时使用默认生成策略(通常基于方法参数) ### 2. 存储数据结构 - **默认序列化方式**:JDK序列化,将整个List序列化为二进制数据,以String类型存储 - **典型存储示**: ```redis SET product:seckill::list "[...jdk序列化字节流...]" ``` - 使用JSON序列化时,会存储为JSON数组格式的字符串 ### 3. 序列化影响 - **JDK序列化问题**:可能导致数据不可读,且不同Java版本存在兼容性问题 - **推荐配置**: ```java @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer()); // JSON序列化 return template; } ``` 使用JSON序列化后,List会存储为类似: ```redis SET orders::list "[{\"id\":1,...},{\"id\":2,...}]" ``` ### 4. 常见问题解析 - **存储类型变化问题**:如引用[2]中出现的List变为对象存储,通常是因为: 1. 方法返回值类型变更(从List变为单个对象) 2. 序列化器配置不一致(不同方法使用不同序列化方式) 3. 键名冲突导致覆盖原有数据 ### 5. 扩展配置建议 - **设置过期时间**:通过RedisCacheManager配置全局或指定缓存的过期时间[^3] ```java cacheManager.setDefaultExpiration(60); // 全局默认60秒 expiresMap.put("product:seckill", 3600L); // 指定缓存过期时间 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值