从零搭建Spring Boot脚手架:整合Redis作为缓存

网友投稿 668 2023-05-20

从零搭建Spring Boot脚手架:整合Redis作为缓存

从零搭建Spring Boot脚手架:整合Redis作为缓存

前言

今天我们会把缓存也集成进来。缓存是一个系统应用必备的一种功能,除了在减轻数据库的压力之外。还在存储一些短时效的数据场景中发挥着重大作用,比如存储用户Token、短信验证码等等,目前缓存的选型还是比较多的,EHCACHE、HAZELCAST、CAFFEINE、COUCHBASE以及本文要整合的REDIS。接下来我们将会在kono脚手架项目中集成Spring Cache以及Redis。

2. 整合目标

使项目具有缓存功能,同时将默认的JDK序列化修改为Jackson序列化以存储一些对象,同时实现一些特定的个性化的缓存空间以满足不同场景下的不同缓存TTL时间需求。

3. 依赖集成

目前只需要引入下面的依赖即可:

默认情况下spring-data-redis使用高性能的lettuce客户端实现,当然你可以替换为老旧的jedis。

4. 缓存及 Redis 配置

缓存以及Redis相关的配置项分别为spring.cache和spring.redis开头的配置,这里比较简单的配置为:

spring:   redis:     host: localhost     port: 6379   cache: #   type: REDIS     redis:     # 全局过期时间       time-to-live: 120

5. RedisTemplate 个性化

默认情况下会有两个模板类被注入Spring IoC供我们使用,需要个性化配置来满足实际的开发。

一个是RedisTemplate,主要用于对象缓存,其默认使用JDK序列化,我们需要更改其序列化方式解决一些问题,比如Java 8日期问题、JSON序列化问题。需要我们重写一下。

/**  * Redis的一些自定义配置.  *  * @author felord.cn  * @since 2020 /8/17 20:39  */ @ConditionalOnClass(ObjectMapper.class) @Configuration(proxyBeanMethods = false) public class RedisConfiguration {     /**      * Redis template redis template.      *      * @param redisConnectionFactory the redis connection factory      * @return the redis template      */     @Bean("redisTemplate")     public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {         RedisTemplate template = new RedisTemplate<>();         template.setConnectionFactory(redisConnectionFactory);         // 使用Jackson2JsonRedisSerialize 替换默认序列化         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = initJacksonSerializer();         // 设置value的序列化规则和 key的序列化规则         template.setValueSerializer(jackson2JsonRedisSerializer);         template.setKeySerializer(new StringRedisSerializer());         template.afterPropertiesSet();         return template;     }      /**      * 处理redis序列化问题      * @return Jackson2JsonRedisSerializer      */     private Jackson2JsonRedisSerializer initJacksonSerializer() {         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);         ObjectMapper om = new ObjectMapper();         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);         //以下替代旧版本 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);         om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);         //bugFix Jackson2反序列化数据处理LocalDateTime类型时出错         om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);         // java8 时间支持         om.registerModule(new JavaTimeModule());         jackson2JsonRedisSerializer.setObjectMapper(om);         return jackson2JsonRedisSerializer;     }  }

另一个是StringRedisTemplate,主要处理键值都是字符串的缓存,采用默认就好。

6. 缓存个性化

使用Spring Cache做缓存的时候,有针对不同的key设置不同过期时间的场景。比如Jwt Token我想设置为一周过期,而验证码我想设置为五分钟过期。这个怎么实现呢?需要我们个性化配置RedisCacheManager。首先我通过枚举来定义这些缓存及其TTL时间。例如:

/**  * 缓存定义枚举  *  * @author felord.cn  * @see cn.felord.kono.configuration.CacheConfiguration  * @since 2020/8/17 21:40  */  public enum CacheEnum {      /**      * 用户jwt token 缓存空间 ttl 7天      */     JWT_TOKEN_CACHE("usrTkn", 7 * 24 * 60 * 60),     /**      * 验证码缓存 5分钟ttl      */     SMS_CAPTCHA_CACHE("smsCode", 5 * 60);      /**      * 缓存名称      */     private final String cacheName;     /**      * 缓存过期秒数      */     private final int ttlSecond;      CacheEnum(String cacheName, int ttlSecond) {         this.cacheName = cacheName;         this.ttlSecond = ttlSecond;     }      public String cacheName() {         return this.cacheName;     }       public int ttlSecond() {         return this.ttlSecond;     } }

这样就能很清楚地描述个性化的缓存了。

然后我们通过向Spring IoC分别注入RedisCacheConfiguration和RedisCacheManagerBuilderCustomizer来个性化配置,你可以留意CacheEnum是如何工作的。如果你有其它的个性化需要也可以对这两个配置类进行定制化。

import cn.felord.kono.enumeration.CacheEnum; import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; import org.springframework.cache.annotation.EnableCaching; 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.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializationContext;  import java.time.Duration; import java.util.EnumSet; import java.util.stream.Collectors;  /**  * redis 缓存配置.  *  * @author felord.cn  * @since 2020 /8/17 20:14  */ @EnableCaching @Configuration public class CacheConfiguration {       /**      * Redis cache configuration.      *      * @param redisTemplate the redis template      * @return the redis cache configuration      */     @Bean     public RedisCacheConfiguration redisCacheConfiguration(RedisTemplate redisTemplate, CacheProperties cacheProperties) {          // 参见 spring.cache.redis         CacheProperties.Redis redisProperties = cacheProperties.getRedis();          RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()                 // 缓存的序列化问题                 .serializeValuesWith(RedisSerializationContext.SerializationPair                         .fromSerializer(redisTemplate.getValueSerializer()));          if (redisProperties.getTimeToLive() != null) {             // 全局 TTL 时间             redisCacheConfiguration = redisCacheConfiguration.entryTtl(redisProperties.getTimeToLive());         }         if (redisProperties.getKeyPrefix() != null) {             // key 前缀值             redisCacheConfiguration = redisCacheConfiguration.prefixCacheNameWith(redisProperties.getKeyPrefix());         }         if (!redisProperties.isCacheNullValues()) {             // 默认缓存null值 可以防止缓存穿透             redisCacheConfiguration = redisCacheConfiguration.disableCachingNullValues();         }         if (!redisProperties.isUseKeyPrefix()) {             // 不使用key前缀             redisCacheConfiguration = redisCacheConfiguration.disableKeyPrefix();         }         return redisCacheConfiguration;     }       /**      * Redis cache manager 个性化配置缓存过期时间.      * @see RedisCacheManager,CacheEnum      * @return the redis cache manager builder customizer      */     @Bean     public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer(RedisCacheConfiguration redisCacheConfiguration) {          return builder -> builder.cacheDefaults(redisCacheConfiguration)                 // 自定义的一些缓存配置初始化 主要是特定缓存及其ttl时间                 .withInitialCacheConfigurations(EnumSet.allOf(CacheEnum.class).stream()                         .collect(Collectors.toMap(CacheEnum::cacheName,                                 cacheEnum -> redisCacheConfiguration.entryTtl(Duration.ofSeconds(cacheEnum.ttlSecond())))));     }  }

个性化的同时我们可以通过@EnableCaching开启Spring Cache缓存支持。关于Spring Cache的细节可以通过文章Spring Cache 详解来了解。

验证Spring Cache Redis缓存个性化

7. 总结

最近事情比较多,所以难得抽出时间来搞一搞。如果你在实际开发中遇到需要整合的功能也可以告诉我,同时如果你发现整合中的一些缺陷或者 Bug 请提交 ISSUE。多多关注:码农小胖哥,跟我一起整合开发脚手架。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解 Redis 内存管理机制和实现
下一篇:Spring中事务的使用、抽象机制及模拟Spring事务实现
相关文章