Spring Cache的使用

一、简介

1. Spring Cache是Spring提供的一个缓存框架,在Spring3.1版本开始支持将缓存添加到现有的spring应用程序中,在4.1开始,缓存已支持JSR-107注释和更多自定义的选项。

1. Spring Cache利用了**AOP**,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,**只需要简单地加一个注解,就能实现缓存功能了,做到了对代码侵入性做小。**

1. 由于市面上的缓存工具实在太多,SpringCache框架还提供了CacheManager接口,可以实现降低对各种缓存框架的耦合。它不是具体的缓存实现,它只提供一整套的接口和代码规范、配置、注解等,用于整合各种缓存方案,比如Caffeine、Guava Cache、Ehcache、**Redis**。

二、常用注解

 三、整合Redis

1、pom文件


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot </groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置(配置类添加@EnableCaching注解)
 

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Resource
    private RedisConnectionFactory factory;


    // 自定义key前缀,例如:cacheName=product.selectOne -> product.selectOne.
    //SEPARATOR=#
    @Bean
    public CacheKeyPrefix cacheKeyPrefix() {
        return cacheName -> cacheName + ".";
    }


    //key生成器
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            if (ObjectUtil.isBasicType(params[0]) || StrUtil.isEmptyIfStr(params[0])) {
                for (Object param : params) {
                    sb.append(param.toString());//基本类型、字符串类型 key直接拼接
                }
            } else {
                sb.append(JSONUtil.toJsonStr(params[0]));//对象类型拼接json字符串 {}
            }
            return sb.toString();
        };
    }

    @Bean//序列化器
    public Jackson2JsonRedisSerializer<Object> serializer() {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule());
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }


    @Bean
    public RedisCacheManager redisCacheManager(Jackson2JsonRedisSerializer<Object> serializer) {

        RedisSerializationContext<Object, Object> serializationContext = RedisSerializationContext.fromSerializer(serializer);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeValuesWith(serializationContext.getValueSerializationPair())//指定redis序列化器
                .computePrefixWith(cacheKeyPrefix());//指定key前缀
        return new CustomRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration);

    }


    static class CustomRedisCacheManager extends RedisCacheManager {
        public static final String SEPARATOR = "#";

        public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
            super(cacheWriter, defaultCacheConfiguration);
        }

        @Override
        protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
            //name=product.selectOne#1800
            String[] arr = StringUtils.delimitedListToStringArray(name, SEPARATOR);
            name = arr[0];//name=product.selectOne
            if (arr.length > 1) {
                long ttl = Long.parseLong(arr[1]);
                cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
            }
            return super.createRedisCache(name, cacheConfig);
        }
    }

}

四、使用

直接在Controller上添加注解

@GetMapping
@Cacheable(value = "product.select#3600")
public List<Product> select(ProductQuery query) {
    return productDao.sel;ect(query);
}


@GetMapping("{id}")
@Cacheable(value = "product.selectById#1800")
public Product selectById(@PathVariable Integer id) {
    return productService.selectOne(id);
}

key示例

五、其他配置

1、缓存击穿配置

@Cacheable(value = "product.selectOne#1800",sync = true)

2、缓存穿透(缓存空值?默认开启) 

#spring.cache.redis.cache-null-values=true

# 配置2(Controller直接配置时间)

 @GetMapping

    @Cacheable(value = "3600")
    public List<Product> select(ProductQuery query) {
        return productDao.select(query);
    }


    @GetMapping("{id}")

    @Cacheable(value = "1800",sync = true)
    public Product selectById(@PathVariable Integer id) {
        return productService.selectOne(id);
    }




 

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {


    @Resource
    private RedisConnectionFactory factory;


    // 自定义key前缀,例如:cacheName=product.selectOne -> product.select.
    //SEPARATOR=#
//    @Bean
//    public CacheKeyPrefix cacheKeyPrefix() {
//        return cacheName -> cacheName + "#";
//    }    
//key生成器
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName()).append(".");
            sb.append(method.getName()).append(".");
            if (ObjectUtil.isBasicType(params[0]) || StrUtil.isEmptyIfStr(params[0])) {
                for (Object param : params) {
                    sb.append(param.toString());//基本类型、字符串类型 key直接拼接
                }
            } else {
                sb.append(JSONUtil.toJsonStr(params[0]));//对象类型拼接json字符串 {}
            }
            return sb.toString();
        };
    }

    @Bean//序列化器
    public Jackson2JsonRedisSerializer<Object> serializer() {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule());
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }


    @Bean
    public RedisCacheManager redisCacheManager(Jackson2JsonRedisSerializer<Object> serializer) {

        RedisSerializationContext<Object, Object> serializationContext = RedisSerializationContext.fromSerializer(serializer);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                .defaultCacheConfig()
                .disableKeyPrefix()//禁用前缀
                .serializeValuesWith(serializationContext.getValueSerializationPair());//指定redis序列化器
                //.computePrefixWith(cacheKeyPrefix()); //指定key前缀cacheable.cacheResolver()

        return new CustomRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration);

    }


    static class CustomRedisCacheManager extends RedisCacheManager {
        //public static final String SEPARATOR = "#";

        public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
            super(cacheWriter, defaultCacheConfiguration);
        }

        @Override
        protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
            //name=product.selectOne#1800
            //String[] arr = StringUtils.delimitedListToStringArray(name, SEPARATOR);
            //if (arr.length > 1) {
                long ttl = Long.parseLong(name);
                cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
            //}
            return super.createRedisCache(name, cacheConfig);
        }
    }

}

Spring CacheSpring框架提供的一种缓存机制,用于提高应用程序的性能和响应速度。通过使用Spring Cache,可以将方法的返回值缓存起来,当下次调用相同的方法时,可以直接从缓存中获取结果,而不需要再执行方法的逻辑。 在使用Spring Cache时,需要进行一些配置。首先,需要添加Redis的配置信息,包括缓存类型、缓存过期时间、缓存键的前缀等。可以通过设置`spring.cache.type`为`redis`来指定使用Redis作为缓存类型。可以使用`spring.cache.redis.time-to-live`设置缓存的过期时间,单位为毫秒。可以使用`spring.cache.redis.key-prefix`设置缓存键的前缀,如果不指定前缀,则默认使用缓存的名字作为前缀。可以使用`spring.cache.redis.use-key-prefix`设置是否使用前缀,默认为true。可以使用`spring.cache.redis.cache-null-values`设置是否缓存空值,以防止缓存穿透。 另外,Spring Cache还支持使用JCache(JSR-107)注解来简化开发。从Spring 3.1开始,定义了`org.springframework.cache.Cache`和`org.springframework.cache.CacheManager`接口来统一不同的缓存技术。 在使用Spring Cache时,可以通过在方法上添加`@Cacheable`注解来启用缓存功能。当调用带有`@Cacheable`注解的方法时,Spring会首先检查缓存中是否存在相应的结果,如果存在,则直接返回缓存中的结果,如果不存在,则执行方法的逻辑,并将结果存入缓存中。 总结起来,使用Spring Cache可以通过配置Redis等缓存信息,并在方法上添加`@Cacheable`注解来实现缓存功能,提高应用程序的性能和响应速度。 #### 引用[.reference_title] - *1* [SpringCache使用](https://blog.youkuaiyun.com/ABestRookie/article/details/121297482)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [springcache使用详解(使用redis做分布式缓存)](https://blog.youkuaiyun.com/A_art_xiang/article/details/125580962)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这孩子叫逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值