常用@Cacheable,使用springcache+redis处理缓存

111 阅读2分钟

springcache支持使用Caffine 和redis等等作为扩展使用。

使用Caffine,这个适合单机,但是不是很好控制。

所以使用redis。

第一个,新建 RedisCacheConfig 类

package com.lzy.myapp.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.CollectionUtils;

import java.time.Duration;

/***
 * caffeine 配置
 * @author ZiYao Lee
 * @date 2022/11/23
 */
@Configuration
@EnableCaching
@Slf4j
public class RedisCacheConfig extends CachingConfigurerSupport {
    @Bean
    @Primary
    @Override   //继承上面这个类,并且加上这个之后才能把它设置为默认的。
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            String re= String.format("%s::%s(%s)",target.getClass().getName(),method.getName(),
                    CollectionUtils.arrayToList(params));//Arrays.asList(params)
            log.debug("缓存生成的key:{}。",re);
            return re;
        };
    }
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(factory);
    // 指定key的序列化方式:string
    redisTemplate.setKeySerializer(RedisSerializer.string());
    // 指定value的序列化方式:json
    redisTemplate.setValueSerializer(RedisSerializer.json());
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    redisTemplate.setHashValueSerializer(RedisSerializer.json());
    return redisTemplate;
}

@Primary
@Bean(name = "cacheManager")
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisCacheConfiguration cacheConfiguration =
            RedisCacheConfiguration.defaultCacheConfig()
                    .disableCachingNullValues()
                    .entryTtl(Duration.ofMinutes(5))
                    .serializeValuesWith(
                            RedisSerializationContext.SerializationPair.fromSerializer(
                                    RedisSerializer.json()));

    return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), cacheConfiguration);
}

@Bean(name = "specCacheManager")
public CacheManager specCacheManager(RedisConnectionFactory factory) {
    RedisCacheConfiguration cacheConfiguration =
            RedisCacheConfiguration.defaultCacheConfig()
                    .disableCachingNullValues()
                    .entryTtl(Duration.ofMinutes(60))
                    .serializeValuesWith(
                            RedisSerializationContext.SerializationPair.fromSerializer(
                                    RedisSerializer.json()));
    return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), cacheConfiguration);
}

二,就是创建 MyRedisCacheManager

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;

import java.time.Duration;

/**
 * xx模块 - MyRedisCacheManager
 *
 * @author 李子耀
 * @version 1.0.0
 * @className MyRedisCacheManager
 * @description MyRedisCacheManager
 * @date 2023-9-25 10:58
 */
public class MyRedisCacheManager extends RedisCacheManager {
    public MyRedisCacheManager(RedisCacheWriter writer, RedisCacheConfiguration defaultCacheConfiguration) {
        super(writer,defaultCacheConfiguration);
    }
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        if(!StringUtils.isEmpty(name) && name.contains("#")) {
            String numStr = name.split("#")[1];
            if(StringUtils.isNumeric(numStr)) {
                return super.createRedisCache(name, cacheConfig.entryTtl(Duration.ofSeconds(Integer.parseInt(numStr))));
            }
        }
        return super.createRedisCache(name, cacheConfig);
    }
}

处理缓存,直接在value集合后面,拼上#加上你的秒数。这样动态生成缓存。

然后就是@Cacheable的使用。

1、可以放在实现类上。

第一种方式key = "'user_id_'+#id",unless = "#result == null")

@Cacheable(value = "user",key = "'user_id_'+#id",unless = "#result == null")

public User selectByPrimaryKey(Integer id) {

return userMapper.selectByPrimaryKey(id);

}

可以读到参数值Integer id

第二种方式key = "'user_id_'+#p0",unless = "#result == null")

@Cacheable(value = "user",key = "'user_id_'+#p0",unless = "#result == null")

public User selectByPrimaryKey(Integer id) {

return userMapper.selectByPrimaryKey(id);

}

也可以读到参数值Integer id

2、可以放在接口上。

第一种方式可以读到Integer id值

@Cacheable(value = "user",key = "'user_id_'+#p0",unless = "#result == null")

User selectByPrimaryKey(Integer id);

第二种方式读不到Integer id值,值是null@Cacheable(value = "user",key = "'user_id_'+#id",unless = "#result == null")

User selectByPrimaryKey(Integer id);

差别就是,放在接口上,只能用p0这个去获取,而不能显式使用字符去获取。

cacheNames 对应上面的@Bean(name = "cacheManager")和@Bean(name = "specCacheManager")。 但是我使用了这个优化MyRedisCacheManager,所以可以默认使用cacheManager。

其他就很方便了。