springboot使用spring cache,基于lettuce连接redis

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/vipbupafeng/article/details/80365380

1、使用lettuce连接工厂连接redis(也可采用springboot方式配置连接)

yml连接配置:

redis:
  cache-one:
    host: localhost
    port: 6379
    database: 0
    password: password

config映射,其他参数可自定义:

@Data
@ConfigurationProperties("redis")
public class RedisConfig {

    private RedisProperties cacheOne;

    /** redis pool最大空闲连接 */
    private int maxIdle = 20;

    /** redis pool最连接数 */
    private int maxTotal = 50;

    /** redis pool最小空闲连接 */
    private int minIdle = 0;

    /** 缓存有效期 */
    private Duration entryTtl = Duration.ofHours(24L);

    /** 连接超时 */
    private Duration connectTimeout = Duration.ofSeconds(15L);

    /** 读取超时 */
    private Duration readTimeout = Duration.ofSeconds(30L);
}

lettuce连接工厂:

default RedisStandaloneConfiguration connection(RedisConfig redisConfig) {
    RedisProperties redisProperties = redisConfig.getCacheOne();
    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    redisStandaloneConfiguration.setHostName(redisProperties.getHost());
    redisStandaloneConfiguration.setPort(redisProperties.getPort());
    redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
    redisStandaloneConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
    return redisStandaloneConfiguration;
}
default RedisConnectionFactory lettuceConnectionFactory(RedisConfig redisConfig) {
    GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
    poolConfig.setMaxIdle(redisConfig.getMaxIdle());
    poolConfig.setMaxTotal(redisConfig.getMaxTotal());
    poolConfig.setMinIdle(redisConfig.getMinIdle());
    LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
            .commandTimeout(Duration.ofSeconds(15))
            .poolConfig(poolConfig)
            .shutdownTimeout(Duration.ZERO)
            .build();
    LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(connection(redisConfig), lettuceClientConfiguration);
    lettuceConnectionFactory.afterPropertiesSet();
    return lettuceConnectionFactory;
}

2、java config注入RedisCacheManager

继承CachingConfigurerSupport类,重写keyGenerator和cacheManager方法并注入spring

@Slf4j
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisConfig.class)
public class RedisCacheConfig extends CachingConfigurerSupport implements LettuceConnection {

    @Autowired
    private RedisConfig redisConfig;

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(":");
            sb.append(method.getName());
            if (ArrayUtils.isNotEmpty(params)) {
                String collect = Arrays.stream(params).map(x -> x.getClass().getSimpleName()).collect(Collectors.joining(",", "(", ")"));
                sb.append(collect);
            }
            return sb.toString();
        };
    }

    @Bean
    @Override
    @ConditionalOnProperty({"redis.cache-one.host"})
    public RedisCacheManager cacheManager() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer()))
                .entryTtl(redisConfig.getEntryTtl());
        RedisCacheManager cacheManager = RedisCacheManager.builder(lettuceConnectionFactory(redisConfig))
                .cacheDefaults(redisCacheConfiguration)
                .transactionAware()
                .build();
        cacheManager.afterPropertiesSet();
        log.info("RedisCacheManager config success");
        return cacheManager;
    }
}

3、序列化/反序列化

序列化配置:

default FastJsonRedisSerializer<Object> fastJsonRedisSerializer() {
    ParserConfig.getGlobalInstance().addAccept("com.demo.entity.");
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setSerializerFeatures(
            SerializerFeature.WriteNullListAsEmpty,
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.WriteEnumUsingToString,
            SerializerFeature.WriteClassName);
    FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
    fastJsonRedisSerializer.setFastJsonConfig(fastJsonConfig);
    return fastJsonRedisSerializer;
}

redis存储的key和value都有序列化设置

StringRedisSerializer:存进去和取出来都是普通字符串类型

JdkSerializationRedisSerializer:key和value默认序列化方式,存进去是二进制形式,取出来自动还原为原类型,不需要指定还原类型,但需要原类型实现Serializable接口,存取效率最高,数据安全性高,但是数据长度过长占用内存或硬盘空间大

GenericFastJsonRedisSerializer:会生成一个@type属性保存对象类型,默认开启autoTypeSupport,存在安全漏洞问题

GenericJackson2JsonRedisSerializer:会生成一个@Class属性保存对象类型,默认配置了enableDefaultTyping,存在安全漏洞问题

FastJsonRedisSerializer和Jackson2JsonRedisSerializer:虽然可以序列化成json字符串保存,但是反序列化时必需指定类型否则报错:com.alibaba.fastjson.JSONException: autoType is not support,如果序列化对象存在非Object父类还会报类型转换异常

通过自定义FastJsonRedisSerializer支持自动反序列化并提供安全性:

1、FastJsonConfig中配置SerializerFeature.WriteClassName

2、配置全局白名单ParserConfig.getGlobalInstance().addAccept("com.package.entity."),指定反序列化包名,多个包配置多个addAccept

3、如果步骤2配置后仍然报错,则可以开启全局AutoTypeSupport,但会存在一定风险,

ParserConfig.getGlobalInstance().setAutoTypeSupport(true)

注意:白名单配置和AutoTypeSupport都需要全局配置

4、spring cache注解

1、@EnableCaching:注入CacheManger时开启缓存功能,开启@EnableCaching后,yml中spring.cache.type设为none

2、@CacheConfig:注解在类上,统一所有方法的缓存命名空间名称和key

3、@CachePut:更新指定缓存,key存在则覆盖,不存在则插入

4、@CacheEivct:清空指定缓存或所有缓存

5、@Caching:组合注解缓存

以上指定的缓存指的是cacheNames值即默认value值,必须被指定,是一个命名空间,层级之间用冒号:隔开

keyGenerator属性指定被注入spring的KeyGenerator子类Bean

unless用在方法返回之后条件判断,为false时才进行缓存操作

condition用在方法调用之前条件判断,为true时才进行缓存操作

allEntries设为true指定缓存全部过期失效

5、service层集成spring cache

将通用缓存注解设置在service接口中,自定义cacheNames,也可以在serviceImpl中添加缓存注解,重写方法会覆盖父类的缓存

接口中缓存,继承的是mybatis-plus的基础接口:

@CacheConfig(cacheNames = "SchoolGirl")
public interface SchoolGirlService extends IService<SchoolGirl> {

    @Cacheable(key = "#id", unless = "#result==null")
    default SchoolGirl findByIdCache(Serializable id) {
        return selectById(id);
    }

    @CachePut(key = "#entity.id", condition = "#entity!=null")
    default SchoolGirl saveCache(SchoolGirl entity) {
        insertOrUpdate(entity);
        return entity;
    }

    @CacheEvict(key = "#id")
    default boolean deleteByIdCache(Serializable id) {
        return deleteById(id);
    }

    @CacheEvict(allEntries = true)
    default boolean saveBatchCache(List<SchoolGirl> list) {
        return insertOrUpdateBatch(list);
    }
}

猜你喜欢

转载自blog.csdn.net/vipbupafeng/article/details/80365380