侧边栏壁纸
博主头像
小城雨巷 博主等级

行动起来,活在当下

  • 累计撰写 20 篇文章
  • 累计创建 6 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

SpringBoot+Cache(自定义有效时间配置)

Administrator
2023-10-18 / 0 评论 / 0 点赞 / 20 阅读 / 0 字

背景

SprinbBoot的cache是不是支持动态设置缓存注解的,因此本次自己实现一个可以动态设置缓存时间的配置。

步骤

引入依赖

	<!-- springboot整合redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.5.6</version>
        </dependency>
        <!-- springboot cache -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.7.4</version>
        </dependency>
        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <!-- jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>

yml 配置

spring:
  cache:
    type: redis
  redis:
    database: 0
    host: localhost
    port: 6379
    password:
    key:
      prefix: CACHE_
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
        timeout: 10000

自定义一个RedisCacheManager


import lombok.SneakyThrows;
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;

/**
 * @author outengfei
 * @date 2023/2/7 9:03
 */
public class CustomRedisCacheManager extends RedisCacheManager {

    public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }

    @SneakyThrows
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfiguration){
        if(!name.isEmpty() && name.contains(":")){
            String[] spelStr = name.split(":");
            String key = spelStr[0];
            String valueStr = spelStr[1];
            int cycleTime = Integer.parseInt(valueStr);
            return super.createRedisCache(key, cacheConfiguration.entryTtl(Duration.ofSeconds(cycleTime)));
        }
        return super.createRedisCache(name, cacheConfiguration);

    }
}



使用自定义的RedisCacheManager覆盖springBoot的RedisCacheManager

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author outengfei
 * @date 2023/2/7 9:04
 */
@Configuration
public class RedisConfig {

    @Value("${spring.redis.key.prefix}")
    private String keyPreFix;

    /**
     * redis序列化方式
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory){
        //指定Jackson2JsonRedisSerializer为Object的序列化器,替代redis默认的序列化器JdkSerializationRedisSerializer
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        ObjectMapper objectMapper = new ObjectMapper();
        //注意:enableDefaultTyping方法已过期
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        //扩展知识:JsonTypeInfo.As属性认知
        //JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性
        //JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性
        //JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性
        //JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象
        //JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组

        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        //反序列化时智能识别变量名(识别没有按驼峰格式命名的变量名)
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //反序列化如果有多的属性,不抛出异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //反序列化如果碰到不识别的枚举值,是否作为空值解释,true:不会抛不识别的异常, 会赋空值,false:会抛不识别的异常
        objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();

        return redisTemplate;

    }


    /*
     * @description Redis缓存的序列化方式使用redisTemplate.getValueSerializer(),不在使用JDK默认的序列化方式
     * @param redisTemplate
     * @return RedisCacheManager
     **/
    @Bean
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
                //使用prefixCacheNameWith需要注意系统自动拼接的双”:“问题
                .computePrefixWith(cacheName -> keyPreFix  + ":" + cacheName + ":")
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getKeySerializer()));
        //return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
        return new CustomRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }
}

测试

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * @author outengfei
 * @date 2023/2/7 9:14
 */
@Slf4j
@Service
public class TestService {

    /**
     * value 【:后面代表缓存时间  单位 /秒】
     * @param key
     * @return
     */
    @Cacheable(value = "data:200000", key = "#key")
    public Object getTestData(String key){

        return System.currentTimeMillis();
    }

    /**
     * value 【:后面代表缓存时间  单位 /秒】
     * @param key
     * @return
     */
    @Cacheable(value = "date:5", key = "#key")
    public Object getTestDate(String key){

        return LocalDateTime.now().toString();
    }

    /**
     * 删除缓存
     * @param key
     */
    @CacheEvict(value = "data", key = "#key")
    public void delete(String key) {

    }
}


0

评论区