spring 注解 @Cacheable自定义单个key设置超时时间

关于spring 注解 @Cacheable自定义单个key的超时时间

今天在研究缓存,@Cacheable注解,可设置value,key,cacheManage,key可以是相关的传入值作为参数,下面有栗子,想设置单个key的缓存时间,但是没有,只是全局设置,要么不设置,这样很大可能会造成缓存一时全失效,有个专业词我也不记得了。

查看源码得知,有一个类对redis进行处理,是DefaultRedisCacheWriter,但是此类是没有被修饰符所修饰的,所以只能包类使用,不能被继承,所以也不能被重写方法
里面有几个方法:

class DefaultRedisCacheWriter implements RedisCacheWriter {

	@Override
		public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
		。。。
	}
	
	@Override
		public byte[] get(String name, byte[] key) {
		。。。
	}
}

所以只能实现RedisCacheWriter ,里面有4个方法,实现即可,我是基本上从DefaultRedisCacheWriter上拷贝实现,然后加以修改的,莫见怪

	void put(String name, byte[] key, byte[] value, @Nullable Duration ttl);

	/**
	 * Get the binary value representation from Redis stored for the given key.
	 *
	 * @param name must not be {@literal null}.
	 * @param key must not be {@literal null}.
	 * @return {@literal null} if key does not exist.
	 */
	@Nullable
	byte[] get(String name, byte[] key);

	/**
	 * Write the given value to Redis if the key does not already exist.
	 *
	 * @param name The cache name must not be {@literal null}.
	 * @param key The key for the cache entry. Must not be {@literal null}.
	 * @param value The value stored for the key. Must not be {@literal null}.
	 * @param ttl Optional expiration time. Can be {@literal null}.
	 * @return {@literal null} if the value has been written, the value stored for the key if it already exists.
	 */
	@Nullable
	byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl);

	/**
	 * Remove the given key from Redis.
	 *
	 * @param name The cache name must not be {@literal null}.
	 * @param key The key for the cache entry. Must not be {@literal null}.
	 */
	void remove(String name, byte[] key);

	/**
	 * Remove all keys following the given pattern.
	 *
	 * @param name The cache name must not be {@literal null}.
	 * @param pattern The pattern for the keys to remove. Must not be {@literal null}.
	 */
	void clean(String name, byte[] pattern);

下面就是实现了,且看

第一步,实现(这里只把put方法拷贝进来,其他的都可自行实现)


//rediskey相关类
public class RedisKeys {
    
    final static String REDIS_EXPIRE_TIME_KEY = "#key_expire_time";

}


//缓存写入实现
public class RedisCacheWriterCustomer implements RedisCacheWriter {


    private final RedisConnectionFactory connectionFactory;

    private final Duration sleepTime;



    /**
     * @param connectionFactory must not be {@literal null}.
     */
    RedisCacheWriterCustomer(RedisConnectionFactory connectionFactory) {
        this(connectionFactory, Duration.ZERO);
    }

    /**
     * @param connectionFactory must not be {@literal null}.
     * @param sleepTime sleep time between lock request attempts. Must not be {@literal null}. Use {@link Duration#ZERO}
     *          to disable locking.
     */
    RedisCacheWriterCustomer(RedisConnectionFactory connectionFactory, Duration sleepTime) {

        Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
        Assert.notNull(sleepTime, "SleepTime must not be null!");

        this.connectionFactory = connectionFactory;
        this.sleepTime = sleepTime;
    }

    @Override
    public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {

        Assert.notNull(name, "Name must not be null!");
        Assert.notNull(key, "Key must not be null!");
        Assert.notNull(value, "Value must not be null!");

        execute(name, connection -> {

            //当设置了过期时间,则修改取出
            //@Cacheable(value="user-key#key_expire=1200",key = "#id",condition = "#id != 2")
            //name 对应 value
            //key 对应 value :: key
            
            //判断name里面是否设置了过期时间,如果设置了则对key进行缓存,并设置过期时间
            int index = name.lastIndexOf(RedisKeys.REDIS_EXPIRE_TIME_KEY);
            if (index  > 0){
                //取出对应的时间 1200 index + 1是还有一个=号
                String expireString = name.substring(index  + 1 + RedisKeys.REDIS_EXPIRE_TIME_KEY.length());
                long expireTime = Long.parseLong(expireString);
                connection.set(key, value, Expiration.from(expireTime,TimeUnit.SECONDS), RedisStringCommands.SetOption.upsert());
            }else if (shouldExpireWithin(ttl)) {
                connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), RedisStringCommands.SetOption.upsert());
            } else {
                connection.set(key, value);
            }
            return "OK";
        });
    }

}

第二步: 把实现的类加入到缓存管理器中

//新建一个配置类

@Configuration

@EnableCaching //开启缓存,默认是rendis缓存,继承CachingConfigurerSupport ,直接重写里面的方法
public class RedisConfig extends CachingConfigurerSupport {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    @Bean
    public CacheManager cacheManager() {
	
        RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
		//上面实现的缓存读写
        RedisCacheWriterCustomer cachaWriterCustomer 
        = new RedisCacheWriterCustomer(connectionFactory);

        CacheManager cm 
        = new RedisCacheManager(cachaWriterCustomer,redisCacheConfiguration());

        return cm;
    }
 @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){

        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();

        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).entryTtl(Duration.ofSeconds(30));

        return configuration;
    }

}

第三步 :在需要的方法上添加注解即可


 	@RequestMapping("/cacheable")
 	//只是此处有点不雅观
    @Cacheable(value="user-key"+ RedisKeys.REDIS_EXPIRE_TIME_KEY +"="+ 1200,key = "#id",condition = "#id != 2")
    @ResponseBody
    public Product CacheableTest(Long id){
    System.out.println("你可还好");
    return "你可还好";
    }
    

看结果
spring 注解 @Cacheable自定义单个key设置超时时间_第1张图片
spring 注解 @Cacheable自定义单个key设置超时时间_第2张图片
spring 注解 @Cacheable自定义单个key设置超时时间_第3张图片

所以现在每次都是从缓存中取,并且设置了过期时间,这里并没有实现重新拿更新过期时间,有需要的再到get()方法中实现。

完。。。

你可能感兴趣的:(springboot)