1. 前言

上一文咱们整合了Mybatis Plus,明天咱们会把缓存也集成进来。缓存是一个零碎利用必备的一种性能,除了在加重数据库的压力之外。还在存储一些短时效的数据场景中施展着重大作用,比方存储用户Token、短信验证码等等,目前缓存的选型还是比拟多的,EHCACHEHAZELCASTCAFFEINECOUCHBASE以及本文要整合的REDIS。接下来咱们将会在kono脚手架我的项目中集成Spring Cache以及Redis

Gitee: https://gitee.com/felord/kono day05 分支

GitHub: https://github.com/NotFound40... day05 分支

2. 整合指标

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

3. 依赖集成

目前只须要引入上面的依赖即可:

 <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-cache</artifactId></dependency><dependency>    <groupId>org.apache.commons</groupId>    <artifactId>commons-pool2</artifactId></dependency>       

默认状况下spring-data-redis应用高性能的lettuce客户端实现,当然你能够替换为老旧的jedis

4. 缓存及Redis配置

缓存以及Redis相干的配置项别离为spring.cachespring.redis结尾的配置,这里比较简单的配置为:

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

5. RedisTemplate个性化

默认状况下会有两个模板类被注入Spring IoC供咱们应用,须要个性化配置来满足理论的开发。

一个是RedisTemplate<Object, Object>,次要用于对象缓存,其默认应用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<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {        RedisTemplate<Object, Object> template = new RedisTemplate<>();        template.setConnectionFactory(redisConnectionFactory);        // 应用Jackson2JsonRedisSerialize 替换默认序列化        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = initJacksonSerializer();        // 设置value的序列化规定和 key的序列化规定        template.setValueSerializer(jackson2JsonRedisSerializer);        template.setKeySerializer(new StringRedisSerializer());        template.afterPropertiesSet();        return template;    }    /**     * 解决redis序列化问题     * @return Jackson2JsonRedisSerializer     */    private Jackson2JsonRedisSerializer<Object> initJacksonSerializer() {        Jackson2JsonRedisSerializer<Object> 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别离注入RedisCacheConfigurationRedisCacheManagerBuilderCustomizer 来个性化配置,你能够注意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@Configurationpublic class CacheConfiguration {    /**     * Redis cache configuration.     *     * @param redisTemplate the redis template     * @return the redis cache configuration     */    @Bean    public RedisCacheConfiguration redisCacheConfiguration(RedisTemplate<Object, Object> 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操作缓存才会达到上图的成果。命令行操作须要显式的申明指令。

7. 总结

最近事件比拟多,所以难得抽出工夫来搞一搞。如果你在理论开发中遇到须要整合的性能也能够通知我,同时如果你发现整合中的一些缺点或者Bug请提交ISSUE。多多关注:码农小胖哥,跟我一起整合开发脚手架。

关注公众号:Felordcn 获取更多资讯

集体博客:https://felord.cn