Spring Cache

1 篇文章 0 订阅

官方文档

https://spring.io/guides/gs/caching/
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-caching
https://docs.spring.io/spring-data/redis/docs/current/reference/html/

核心原理

Spring Cache框架由CacheCacheManager两个组件组成。
Cache定义缓存操作的接口标准,使用底层缓存(如Ehcache、redis等)实现。
CacheManager则是对Cache的管理接口,并提供额外的配置服务。
spring缓存实现原理

源码解读参考:
SpringCache实现原理及核心业务逻辑(一)
SpringCache实现原理及核心业务逻辑(二)
SpringCache实现原理及核心业务逻辑(三)

Spring Boot默认实现

Cache实现:org.springframework.cache.concurrent.ConcurrentMapCache
CacheManager实现:org.springframework.cache.concurrent.ConcurrentMapCacheManager
自动配置:SimpleCacheConfiguration

@SpringBootApplication
public class Application implements CommandLineRunner{
    @Autowired
    private CacheManager cacheManager;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) {
        System.out.println(cacheManager.getClass());
        System.out.println(cacheManager.getCache("test").getClass());
    }
}
class org.springframework.cache.concurrent.ConcurrentMapCacheManager
class org.springframework.cache.concurrent.ConcurrentMapCache

缓存使用

Spring提供了一套@Cacheable@CachePut@CacheEvict注解对缓存进行操作,实际上是使用AOP对CacheManager、Cache进行封装。
在配置类上加上@EnableCaching注解,Spring Cache才会生效。
这三个注解的使用:
https://www.cnblogs.com/imyijie/p/6518547.html
缓存key支持的EL表达式上下文:
https://blog.csdn.net/m0_37962779/article/details/78747619
自定义缓存数据 key 生成策略:
https://blog.csdn.net/defonds/article/details/48716161
注意和限制:
https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/index.html

Spring Boot集成redis

添加spring-boot-starter-data-redis后,Spring Boot自动识别redis,使用redis的Cache和CacheMager实现来操作缓存。
Cache实现:org.springframework.data.redis.cache.RedisCache
CacheManager实现:org.springframework.data.redis.cache.RedisCacheManager
自动配置:org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
案例可参考:
https://blog.csdn.net/abombhz/article/details/78123253?locationNum=6&fps=1
https://my.oschina.net/mrfu/blog/1631805

Spring Boot不同版本配置会不太一样,以下都以Spring Boot2.0.1版本为例。

redis属性

完整属性参考:RedisProperties

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0  
# Redis服务器地址
spring.redis.host=192.168.0.58
# Redis服务器连接端口
spring.redis.port=6379  
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait = PT-0.001S
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0

redis缓存配置

缓存配置类:RedisCacheConfiguration

配置名称说明默认值application.properties
ttl全局生存时间0spring.cache.redis.timeToLive
cacheNullValues是否缓存空值truespring.cache.redis.cacheNullValues
usePrefix是否使用前缀truespring.cache.redis.useKeyPrefix
keyPrefix前缀表达式cacheName + “::”spring.cache.redis.keyPrefix
keySerializationPair缓存key的序列化器StringRedisSerializer
valueSerializationPair缓存value的序列化器JdkSerializationRedisSerializer
  • conversionService
格式转换器DefaultFormattingConversionService
/**
 * 默认缓存配置
 */
public static RedisCacheConfiguration defaultCacheConfig() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        registerDefaultConverters(conversionService);
        return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(),
                SerializationPair.fromSerializer(new StringRedisSerializer()),
                SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()), conversionService);
    }

自定义配置

下面是我项目使用的配置:

@EnableCaching
@Configuration
public class CacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(defaultCacheConfig())
            .withInitialCacheConfigurations(getCacheConfig())
            .transactionAware()
            .build();
    }

    /**
     * 对每一个缓存单独配置TTL,value序列化器使用Jackson2JsonRedisSerializer
     */
    private Map<String,RedisCacheConfiguration> getCacheConfig(){
        Map<String,RedisCacheConfiguration> cacheConfigurations = new HashMap<>(16);
        for (CacheType cacheType : CacheType.values()) {
            RedisCacheConfiguration config = defaultCacheConfig()
                .entryTtl(cacheType.getTtl())
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(cacheType.getClz())));
            cacheConfigurations.put(cacheType.getCacheName(),config);
        }
        return cacheConfigurations;
    }

    /**
     * 自定义全局配置
     */
    @Bean
    RedisCacheConfiguration defaultCacheConfig(){
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.of(30, ChronoUnit.MINUTES))
            .computePrefixWith(cacheName -> "liyuan-cache:" + cacheName + ":");
    }
}
public interface CacheConstant {
    String USER_CACHE_NAME_1 = "user-id";
    String USER_CACHE_NAME_2 = "user-account";
    String ITEM_CACHE_NAME_1 = "item-id";
    String ITEM_CACHE_NAME_2 = "item-name";
}
public enum CacheType {
    USER_BY_ID(CacheConstant.USER_CACHE_NAME_1,Duration.of(60, ChronoUnit.MINUTES),User.class),
    USER_BY_ACCOUNT(CacheConstant.USER_CACHE_NAME_2,Duration.of(60, ChronoUnit.MINUTES),User.class),
    ITEM_BY_ID(CacheConstant.ITEM_CACHE_NAME_1,Duration.of(1, ChronoUnit.DAYS),Item.class),
    ITEM_BY_NAME(CacheConstant.ITEM_CACHE_NAME_2,Duration.of(1, ChronoUnit.DAYS),Item.class);

    CacheType(String cacheName, Duration ttl, Class<?> clz) {
        this.cacheName = cacheName;
        this.ttl = ttl;
        this.clz = clz;
    }

    /**
     * 缓存名称
     */
    private String cacheName;
    /**
     * 存活时间
     */
    private Duration ttl;
    /**
     * 缓存对象
     */
    private Class<?> clz;

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public Duration getTtl() {
        return ttl;
    }

    public void setTtl(Duration ttl) {
        this.ttl = ttl;
    }

    public Class<?> getClz() {
        return clz;
    }

    public void setClz(Class<?> clz) {
        this.clz = clz;
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheTest {

    @Autowired
    private RedisCacheManager redisCacheManager;

    @Test
    public void test() throws Exception {
        Cache cache = redisCacheManager.getCache(CacheConstant.USER_CACHE_NAME_1);
        cache.evict(1);
        Cache.ValueWrapper valueWrapper = cache.get(1);
        Assert.assertNull(valueWrapper);
        cache.put(1,new User(1,"liyuan"));
        valueWrapper = cache.get(1);
        Assert.assertNotNull(valueWrapper);
        User user = (User)valueWrapper.get();
        Assert.assertEquals("liyuan",user.getName());

    }
}

其它引用

https://blog.csdn.net/qq_21806621/article/details/79671257

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值