Spring @Cacheable缓存注解

一、简介

缓存介绍

缓存,在我们的日常开发中用的非常多,是我们应对各种性能问题支持高并发的一大利器。

  • Spring 从 3.1 开始就引入了缓存的支持。定义了如下两个接口来统一支持不同的缓存技术。

    • org.springframework.cache.Cache
    • org.springframework.cache.CacheManager
  • 我们熟知的缓存有:堆缓存(Ehcache3.xGuava CacheCaffeine等)、堆外缓存(Ehcache3.xMapDB等)、分布式缓存RedisMemcached等)等等。

  • 常用的缓存注解:@EnableCaching@Cacheable@CachePut@CacheEvict

Cache 和 CacheManager 接口说明

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

二、缓存实战

1.开启缓存

在 SpringBoot 的启动类上添加注解@EnableCaching

2.@Cacheable

@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存。

常用属性:

  • cacheNamesvalue:用来指定缓存组件名称。

    @Cacheable(cacheNames = "users", key="#id")
    public User getUser(Integer id) {}
    
  • key:缓存数据的 key,可以用它来指定。默认使用所有参数的值进行组合。(key可以使用 spEL 表达式来编写)。

    @Cacheable(cacheNames = "usersBySpEL", key="#root.methodName + '[' + #id + ']'")
    public User getUserBySpEL(Integer id) {}
    
  • keyGenerator:key 的生成器。key 和 keyGenerator 二选一使用。

    @Cacheable(cacheNames = "userByKeyGenerator", keyGenerator = "myKeyGenerator")
    public User getUserByKeyGenerator(Integer id) {}
    
  • condition:指定符合条件的情况下才缓存。

    @Cacheable(cacheNames = "userByCondition", condition = "#id > 1")
    public User getUserByCondition(Integer id) {}
    
  • unless:指定不符合条件的情况下才缓存。(可以获取到结果进行判断,通过 #result 获取方法结果,unless,汉语意思,除非,指会缓存,除了。。。之外)。

    @Cacheable(cacheNames = "userByUnless", unless = "#id > 1")
    public User getUserByUnless(Integer id) {}
    
  • sync:是否使用异步模式。

3.@CachePut

@CachePut 的作用 主要针对配置,能够根据方法的请求参数对其结果进行缓存。

  • 区别于 @Cacheable,它每次都会触发真实方法的调用,可以保证缓存的一致性。
  • 属性与 @Cacheable 类同。
@CachePut(cacheNames = "users" , key = "#user.id")
public User addUser(User user) {}
4.@CacheEvict

@CacheEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空

常用属性

  • cacheNamesvalue:用来指定缓存组件名称。

  • key:缓存数据的 key,可以用它来指定。默认使用所有参数的值进行组合。(key可以使用 spEL 表达式来编写)。

  • condition:指定符合条件的情况下的缓存。

  • allEntries:是否清空所有缓存,缺省为false。

  • beforeInvocation:是否在方法执行前就清空,缺省为false,缺省情况下,如果方法执行抛异常,则不会清空缓存。

    @CacheEvict(cacheNames = "users", key = "#id")
    public void delUserCache(Integer id) {}

5.@CacheConfig

@CacheConfig 的作用 主要针对类配置,能够设置当前类中 @Cacheable 的 value 属性默认值。当然如果 @Cacheable 设置了 value,还是以设置的值为准。

常用属性

  • cacheNames: 指定缓存名称默认值。
6.@Caching

@Caching 的作用 主要针对方法配置,能够组合多个Cache注解。比如用户新增成功后,我们可能需要添加 id -> user、username -> user、email -> user 的缓存,此时就需要 @Caching 组合多个注解标签了。

常用属性

  • cacheable:组合多个 @Cacheable 注解

  • put:组合多个 @CachePut 注解

  • evict:组合多个 @CacheEvict 注解

    @CacheConfig(cacheNames = "users")
    public class CacheTestServiceImpl implements CacheTestService {
    /**
    * @Cacheable 的 cacheNames 默认为 "users"
    */
    @Cacheable(key="#id")
    public User getUser(Integer id) {...}
    }

7.自定义缓存过期时间

7.1 设置全局默认缓存过期时间:

    // 提供默认的cacheManager,应用于全局,实现存活2天
    @Bean
    @Primary
    public CacheManager defaultCacheManager(
            RedisTemplate<?, ?> redisTemplate) {
        RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisTemplate.getConnectionFactory());
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(2));
        return new RedisCacheManager(writer, config);
    }

7.2 定制部分缓存过期时间

  • 定制缓存过期时间,需要自定义RedisCacheManager来实现ttl设置。

  • 注意:项目中如已配置了RedisCacheManager需要在原配置的bean上添加注解 @Primary,以免造成干扰

      /**
      	自定义RedisCacheManager,用于在使用@Cacheable时设置ttl
       */
      @Bean
      public RedisCacheManager selfCacheManager(RedisTemplate<String, Object> redisTemplate) {
      	RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
      	RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
      			.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
      	return new SelfRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
      }
    

SelfRedisCacheManager.java

public class SelfRedisCacheManager extends RedisCacheManager {
    public SelfRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }

    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        String[] cells = StringUtils.delimitedListToStringArray(name, "=");
        name = cells[0];
        if (cells.length > 1) {
            long ttl = Long.parseLong(cells[1]);
            // 根据传参设置缓存失效时间,默认单位是秒
            cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
        }
        return super.createRedisCache(name, cacheConfig);
    }
}

使用:

// value、cacheNames是等效的,ttl=600s,unless是不缓存的结果(为null时不缓存)
@Cacheable(value = "p_user=600",key = "#menu+'_'+#type+'_'+#userId",cacheManager = "selfCacheManager", unless = "#result == null")
public User getUser(...){
    xxx
}

// 当前方法执行时对应的key失效,也可以用@CachePut在当前方法执行时更新key
@CacheEvict(cacheNames = "p_user",key = "#p.menu+'_'+#p.type+'_'+#p.user")
public boolean setUser(User p){
    xxx
}

三、spEL表达式

参考地址:

1.@Cacheable设置过期时间:https://blog.csdn.net/weixin_41860719/article/details/125226096

相关推荐
代码之光_198021 分钟前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi27 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
鹿屿二向箔1 小时前
基于SSM(Spring + Spring MVC + MyBatis)框架的咖啡馆管理系统
spring·mvc·mybatis
戴眼镜的猴1 小时前
Spring Boot的过滤器与拦截器的区别
spring boot
NoneCoder2 小时前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发
尘浮生2 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料2 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
morris1313 小时前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
想要打 Acm 的小周同学呀4 小时前
LRU缓存算法
java·算法·缓存
hlsd#4 小时前
go 集成go-redis 缓存操作
redis·缓存·golang