SpringBoot Redis Cache

知识点

Spring高版本引入了Cache的注解技术。该技术是一种规范,官方支持的实现包括Generic、JCache(JSR-107)、(EhCache 3,Hazelcast,Infinispan,and others)、EhCache 2.x、Hazelcast、Infinispan、Couchbase、Redis、Caffeine、Simple等。

Redis的Cache技术,底层使用的是Spring Data Redis

Cache技术主要有以下注解@EnableCaching@Cacheable@CacheEvict@CachePut@Caching@CacheConfig,这些注解支持Spring SPEL表达式

注解详解

@EnableCaching:作用于配置类,用来打开SpringBoot的Cache自动装配
@Cacheable:表示被调用的方法先要去缓存中查询,如果命中则返回缓存中的内容,否则调用方法返回并将返回结果存入缓存。
@CacheEvict:表示方法结束后删除缓存,可以通过beforeInvocation=true设置方法执行前删除缓存
@CachePut:用来更新缓存,旧的值会被覆盖,方法一定会执行
@Caching:多个缓存符合操作
@CacheConfig:标注在类上,对类中的方法统一设置缓存操作

Cache配置类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
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.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于Redis的缓存配置
 *
 * @author zhaocy18
 * @date 2023/5/29
 */
@Configuration
@EnableCaching
public class CacheConfig {

    @Value("${spring.application.name}")
    private String appName;

    @Bean
    public KeyGenerator wiselyKeyGenerator() {
        return (object, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(object.getClass().getName()).append("#");
            sb.append(method.getName()).append("-");
            for (Object obj : params) {
                sb.append(obj.toString()).append(",");
            }
            return sb.substring(0, sb.length() - 1);
        };
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                // 默认缓存配置
                .cacheDefaults(defaultCacheConfig(Duration.ofDays(1)))
                // 针对于指定key做自定义操作
                .withInitialCacheConfigurations(initCacheConfig())
                .transactionAware()
                .build();
    }

    /**
     * 设置默认缓存配置
     *
     * @param duration key的有效时间(Duration.ZERO为永不过期)
     * @return RedisCacheConfiguration
     */
    private RedisCacheConfiguration defaultCacheConfig(Duration duration) {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定序列化的作用域(field、get()、set()等)和作用域的访问修饰符
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类不可以是被final修饰的
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        // 设置时间格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        objectMapper.registerModule(javaTimeModule);
        serializer.setObjectMapper(objectMapper);

        return RedisCacheConfiguration.defaultCacheConfig()
                // 格式化cacheName,默认为 cacheName::
                .computePrefixWith(cacheName -> String.format("%s:%s:", appName, cacheName))
                // key的默认超时时间
                .entryTtl(duration)
                // key的序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
                // value的序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
                // 不缓存空值
                .disableCachingNullValues();
    }

    /**
     * 自定义key的缓存设置
     *
     * @return Map<自定义key, 配置>
     */
    private Map<String, RedisCacheConfiguration> initCacheConfig() {
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>(16);
        configMap.put("user", defaultCacheConfig(Duration.ofHours(8)));
        configMap.put("redisTemplate", defaultCacheConfig(Duration.ZERO));
        return configMap;
    }

}

你可能感兴趣的:(redis,spring,boot,spring)