SpringBoot 缓存之 @Cacheable 详细介绍

昨天 2691阅读 0评论

一、简介

1、缓存介绍

Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache(JSR-107)注解简化我们的开发。

其使用方法和原理都类似于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其核心思想是,当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存在缓存中。

2、Cache 和 CacheManager 接口说明
  • Cache 接口包含缓存的各种操作集合,你操作缓存就是通过这个接口来操作的。
  • Cache 接口下 Spring 提供了各种 xxxCache 的实现,比如:RedisCache、EhCache、ConcurrentMapCache
  • CacheManager 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。

    小结:

    每次调用需要缓存功能的方法时,Spring 会检查指定参数的指定目标方法是否已经被调用过,如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

    二、@Cacheable 注解使用详细介绍

    1、缓存使用步骤

    @Cacheable 这个注解,用它就是为了使用缓存的。所以我们可以先说一下缓存的使用步骤:

    1、开启基于注解的缓存,使用 @EnableCaching 标识在 SpringBoot 的主启动类(或配置类)上。
    2、标注缓存注解即可
    

    ① 第一步:开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上

    @SpringBootApplication
    @EnableCaching/**开启基于注解的缓存*/
    @Slf4j
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
            log.info("");
        }
    }
    

    ② 第二步:标注缓存注解

        @Cacheable(value = "test",key = "#id")
        public String test(Integer id){
            System.out.println("经过这里=======>");
            return "这是测试"+id;
        }
    

    注:这里使用 @Cacheable 注解就可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法,若数据过期,需要调用方法查询结果返回并缓存

    2、常用属性说明

    下面介绍一下 @Cacheable 这个注解常用的几个属性:

    • cacheNames/value :用来指定缓存组件的名字
    • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
    • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用
    • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。
    • condition :可以用来指定符合条件的情况下才缓存
    • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
    • sync :是否使用异步模式。
      1. cacheNames/value

        用来指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式,支持指定多个缓存。

      2. key

        缓存数据时使用的 key。默认使用的是方法参数的值。可以使用 spEL 表达式去编写

      3. keyGenerator

        key 的生成器,可以自己指定 key 的生成器,通过这个生成器来生成 key

        SpringBoot 缓存之 @Cacheable 详细介绍 第1张

        SpringBoot 缓存之 @Cacheable 详细介绍 第2张

        这样放入缓存中的 key 的生成规则就按照你自定义的 keyGenerator 来生成。不过需要注意的是:

        @Cacheable 的属性,key 和 keyGenerator 使用的时候,一般二选一。

      4. condition

        符合条件的情况下才缓存。方法返回的数据要不要缓存,可以做一个动态判断。

        SpringBoot 缓存之 @Cacheable 详细介绍 第3张

      5. unless

        否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。

        SpringBoot 缓存之 @Cacheable 详细介绍 第4张

      6. sync

        是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中。

      前面说过,缓存的 key 支持使用 spEL 表达式去编写,下面总结一下使用 spEL 去编写 key 可以用的一些元数据:

      属性名称描述示例
      methodName当前方法名#root.methodName
      method当前方法#root.method.name
      target当前被调用的对象#root.target
      targetClass当前被调用的对象的class#root.targetClass
      args当前方法参数组成的数组#root.args[0]
      caches当前被调用的方法使用的Cache#root.caches[0].name
      3、@CachePut和@CacheEvict 注解使用
      • @CachePut

        将方法返回值存入到缓存中,一般情况下是用在更新操作中,并于Cacheable与CacheEvict配合使用

      • @CacheEvict

        清除缓存值,一般用在删除或更新操作中,并于Cacheable与CachePut配合使用。并且在@CacheEvict注解中,多了两个参数:

        1. allEntries - 清除当前value下的所有缓存
        2. beforeInvocation - 在方法执行前清除缓存

        示例代码示例如下:

        	/**查询,加载缓存*/
        	@Cacheable(value = "c", key = "123")
            public String hello(String name) {
                System.out.println("name - " + name);
                return "hello " + name;
            }
            
            /**更新缓存*/
            @CachePut(value = "c", key = "123")
            public String put() {
                return "hello put";
            }
            
            /**删除缓存*/
            @CacheEvict(value = "c", key = "123")
            public String evict() {
                return "hello put";
            }
        

        三、配置类(结合Redis作为缓存)

        import com.fasterxml.jackson.annotation.JsonAutoDetect;
        import com.fasterxml.jackson.annotation.PropertyAccessor;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.springframework.cache.CacheManager;
        import org.springframework.cache.annotation.CachingConfigurerSupport;
        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.connection.RedisConnectionFactory;
        import org.springframework.data.redis.core.RedisTemplate;
        import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
        import org.springframework.data.redis.serializer.RedisSerializationContext;
        import org.springframework.data.redis.serializer.RedisSerializer;
        import org.springframework.data.redis.serializer.StringRedisSerializer;
        import java.time.Duration;
        /**
         * 缓存配置类
         * */
        @EnableCaching /**开启缓存注解*/
        @Configuration
        public class RedisConfig extends CachingConfigurerSupport {
            @Bean
            public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
                RedisTemplate template = new RedisTemplate();
                RedisSerializer redisSerializer = new StringRedisSerializer();
                Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
                ObjectMapper om = new ObjectMapper();
                om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                jackson2JsonRedisSerializer.setObjectMapper(om);
                template.setConnectionFactory(factory);
                //key序列化方式
                template.setKeySerializer(redisSerializer);
                //value序列化
                template.setValueSerializer(jackson2JsonRedisSerializer);
                //value hashmap序列化
                template.setHashValueSerializer(jackson2JsonRedisSerializer);
                return template;
            }
            @Bean
            public CacheManager cacheManager(RedisConnectionFactory factory) {
                RedisSerializer redisSerializer = new StringRedisSerializer();
                Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
                /**解决查询缓存转换异常的问题*/
                ObjectMapper om = new ObjectMapper();
                om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                jackson2JsonRedisSerializer.setObjectMapper(om);
                /**配置序列化(解决乱码的问题)*/
                RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofSeconds(600))/**设置缓存默认过期时间600秒*/
                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                        .disableCachingNullValues();
                return RedisCacheManager.builder(factory)
                        .cacheDefaults(config)
                        .build();
            }
        }
        

        pom.xml需要Redis依赖:

                
                    org.springframework.boot
                    spring-boot-starter-data-redis
                    2.6.6
                
        

        纯属个人经验,喜欢的可以点赞关注,后续见!!!


免责声明
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明。
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所
提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何
损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在
转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并白负版权等法律责任。

手机扫描二维码访问

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,2691人围观)

还没有评论,来说两句吧...

目录[+]