集成缓存 -- Spring Cache

前言

对于一些后端系统,如果不是电商系统,在前文中的redis集成之后,一般会采用使用redis 封装工具类进行存储一些数据,但是在springBootspring已经集成了缓存中间件,一般来说普通的缓存可以使用缓存中间件进行使用,比如说配置列表,比如说一些固定的json,库存配置,地址配置,状态机配置,对于一般不怎么改动的且并发量在100以内的使用注解配置要舒服的多,今天还是看了一下源码顺便把这个好用的缓存件总结下来。

spring3.1就开始定义了CacheCaheManager 接口来实现工程上面的缓存技术并支持JCache注解来简化开发,具体内容可以参考spring的官网文档。Cache接口为缓存组件规范了定义,包含缓存的各种操作集合

源码
入门

关于缓存管理器接口,提供了 获取缓存,和通过名字获取缓存
在这里插入图片描述

缓存件里面提供了多种缓存中间件,有普通的也有组件化以及redis等缓存管理器
在这里插入图片描述
通过当前map来管理不同名字的缓存
在这里插入图片描述

在赋予缓存名字的时候会根据是否存在命名,如果没有会创建当前map缓存方法
在这里插入图片描述

由上文源码可以了解到

缓存 — 缓存管理器 – 缓存

springBoot 自动配置缓冲中间件。

在这里插入图片描述
通过注入缓存的搜索器去搜索各种缓存配置
在这里插入图片描述
通过mapping来映射缓存类型配置
在这里插入图片描述

缓存类型配置由map集合收纳
在这里插入图片描述
缓存类型枚举
在这里插入图片描述
文中以redis为例 通过映射redis类型获取 redis 缓存配置 通过源码可以看到构造函数 存在redisCacheConfiguration如果不存在默认配置,通过bean帮我们创建好了 CacheManager 管理器
在这里插入图片描述

CacheProperties Application写入的Spring.Cache里面注入过来的缓存名称。
在这里插入图片描述

Spring.Cache 配置
在这里插入图片描述

如果没有缓存名字会自己初始化一个缓存名称
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

拿到管理器之后确定配置 获取管理器配置
在这里插入图片描述

下面关于如果没有redisCacheConfigration那么默认创建可以看到keyString 序列号,值是JDK序列号,如果后期脚本使用那么存储在redis缓存的值需要进行再处理为json
在这里插入图片描述

从文中可以看到,缓存管理器以及缓存只要开启缓存,并配置简单的缓存类型,那么缓存中间件就可以自动化为我们配置好所需要的所有管理器,以及缓存

SpringBoot已经启用自动化配置进行缓存封装,这种情况,以常用的redis 为例进行缓冲示例

介绍几个注解
  • @Cacheable 触发保存到缓存 常用
  • @CacheEvict 触发将缓冲删除
  • @CachePut 不影响方法执行更新
  • @Cacheing 组合多个操作
  • @CacheConfig 在类级别共享缓冲配置

整合SpringCache

引入依赖
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.3.2.RELEASE</version>
        </dependency>

开启缓存

在这里插入图片描述

配置属性
spring.cache.type=redis

spring.cache.redis.time-to-live=6000
# 防止穿透
spring.cache.redis.cache-null-values=true
# 指定前缀 就用指定的前缀,如果没有默认使用缓存名字作为前缀
spring.cache.redis.key-prefix=cache_
spring.cache.redis.use-key-prefix=true

了解注解

在这里插入图片描述

录入测试文本

在这里插入图片描述

测试案例分析

@Cacheable 代表当前结果需要缓存 如果缓存中有 方法不需要调用 ,如果缓存没有查询结果映射到redis缓存中去

	@AliasFor("cacheNames")
	String[] value() default {};
可能遇到的问题,击穿 雪崩 穿透

每个需要缓存的数据 指定业务类型 放到缓存分区管理器中,方便后期从redis 获取

缓存分区 CacheNames 缓存建 key = "#root.methodName"方法名
配置文件 -> spring.cache.redis.key-prefix=cache_ 缓存前缀 cache_

解决雪崩

spring.cache.redis.time-to-live=6000 过期时间 雪崩设置过期时间 6000 毫秒

解决穿透

spring.cache.redis.cache-null-values=true 穿透是否存储null 解决

击穿 设置 注解 sync = true 过期同步线程获取
@Cacheable(value = {"location"},key = "#root.methodName",sync = true)

自定义缓存

前面源码说到, 由于存储值进行的默认是JDK序列, 如果没有RedisCacheConfiguration 才会创建

捋一下思路

 CacheAutoConfiguration ->  getConfigurationClass -> RedisCacheConfiguration ->cacheManager ->   RedisCacheManager ->determineConfiguration ->  判断是否为空->

由于缓存的redis 过期时间为空 且 序列化方式为JDK 序列存储,所以建议定义存储 为 json 方便后面使用

源码构造配置

 //  判断是否为空 ->
 
 config.serializeValuesWith(SerializationPair
				.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));

	RedisCacheConfiguration(CacheProperties cacheProperties,
			CacheManagerCustomizers customizerInvoker,
			ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration) {
		this.cacheProperties = cacheProperties;
		this.customizerInvoker = customizerInvoker;
		this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
	}

改造

@EnableConfigurationProperties(CacheProperties.class)
@Configuration
public class MyCacheConfig {

    /**
     * @ConfigurationProperties(prefix = "spring.cache")
     * public class CacheProperties {
     *
     * @return
     */
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        config.serializeKeysWith( RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}

总结

读多写少 及时性 一致性要求不高的数据, 完全可以使用Srping - Cache 特殊情况需要强及时性及数据一致性,可以进行特殊设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值