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 "你可还好";
    }
    

看结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

完。。。

Spring框架通过Spring Cache提供了一套强大的缓存体系,可以轻松地实现缓存数据,提高应用程序的性能。Spring框架提供了三个主要的注解来实现缓存:@Cacheable、@CachePut和@CacheEvict。 @Cacheable注解用于将方法的结果缓存起来,以便在下次请求时,如果参数相同,则可以直接从缓存中获取结果,而不需要重新计算。该注解适用于如果计算结果比较耗时,或者需要从数据库或其他外部资源中提取数据的情况。 @CachePut注解用于更新缓存中的数据。它与@Cacheable注解类似,但不同的是,它总是更新缓存数据,而不管缓存中是否已经存在该key的值。所以,可以使用这个注解来更新缓存中的数据。 @CacheEvict注解用于从缓存中删除数据。它在需要删除缓存数据的情况下使用。它可以删除指定的key对应的缓存,也可以清空所有缓存数据。 这三个注解都有一个可选参数Named:如果指定了该参数,则缓存将使用指定的名称使用。如果未指定,则使用默认的名称。可以使用不同名称的缓存来存储不同类型的数据,并使用不同的缓存策略来控制它们的存储方式。 除了Spring自带的缓存提供者之外,还可以使用其他的缓存提供者,如Ehcache、Redis、Memcached等等。在使用缓存时,需要注意的是,不同的缓存提供者之间可能会有不同的限制和性能差异。因此,必须根据实际情况选择最适合的缓存提供者和缓存策略,以获取最好的性能和可靠性。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值