pring 定义 CacheManager 和 Cache 接口用来统一不同的缓存技术。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 集成 Cache 的时候,我们需要注册实现的 CacheManager 的 Bean。

Spring Boot 为我们自动配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、GuavaCacheConfiguration、RedisCacheConfiguration、SimpleCacheConfiguration 等。
在我们不使用其他第三方缓存依赖的时候,springboot自动采用ConcurrenMapCacheManager作为缓存管理器。


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

• Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
• Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache ,ConcurrentMapCache等;

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

• 使用Spring缓存抽象时我们需要关注以下两点;

1、确定方法需要被缓存以及他们的缓存策略
2、从缓存中读取之前缓存存储的数据

几个重要概念&缓存注解


Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager 缓存管理器,管理各种缓存(Cache)组件

@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存。
@EnableCaching 开启基于注解的缓存

keyGenerator 缓存数据时key生成策略

serialize 缓存数据时value序列化策略(是Java序列化方式还是转成json方式等等)


2.缓存注解



Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用


@Cacheable(添加缓存)



主要针对可缓存的方法配置,如查找方法

注解作用

先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中



几个属性:
cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
key:缓存数据使用的key;可以用它来指定。如果不指定,默认是使用方法参数的值 1-方法的返回值 key也可以编写SpEL; #i d;参数id的值 #a0 #p0 #root.args[0]
getEmp[2]

  1. keyGeneratorkey的生成器;可以自己指定key的生成器的组件id<br /> key/keyGenerator:二选一使用,两个不能一起使用;<br /> cacheManager:指定缓存管理器(指定从哪个缓存管理器里面拿到缓存);或者cacheResolver指定获取解析器,<br />缓存管理器和缓存解析器只能是二选一选一个,作用都一样 condition:指定符合条件的情况下才缓存,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存<br /> ,condition = "#id>0"<br /> condition = "#a0>1":第一个参数的值》1的时候才进行缓存<br /> unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存,和condition是相仿的;可以获取到结果进行判断 unless = "#result == null"<br /> unless = "#a0==2":如果第一个参数的值是2,结果不缓存;<br /> sync:是否使用异步模式<br /> <br />value : 缓存的名称,在 spring 配置文件中定义,必须指定至少一个<br /> <br />

@CachePut(更新缓存)


应用到写数据的方法上.比如 新增 修改 方法

调用方法的时候会自动把相应的数据放入缓存

value :缓存的名字,Spring配置文件中定义,必须指定至少一个
key: 缓存的key,可以为空,如果指定要按照SpELl表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
condition: 缓存的条件,可以为空,使用SpEl编写,返回true或者false,只有true才进行缓存

@CacheEvict(删除缓存)

说明:
主要针对移除数据的方法配置,如删除方法
调用方法时,根据一定的条件会从缓存中移除相应的数据
参数:
value :
缓存的名称,在 spring 配置文件中定义,必须指定至少一个
key
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
condition
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存
allEntries
是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
beforeInvocation
是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

缺陷

1.不支持TTL,也就是不能设置expires time。这点挺遗憾的,spring-cache认为这是各个cache实现自己去完成的事情,有方案但是只能设置统一的过期时间,这明显不够灵活。比如用户的抽奖次数、有效期等业务,当天有效,或者3天、一周有效,我们倾向于设置缓存有效期解决这个问题,而spring-cache却无法完成。
2.无法根据查询结果中的内容生成缓存key,比如getUser(uid)方法,想通过查询出来的user.email生成缓存key就无法实现了。
3.调试起来麻烦


(二)基于代码的Cache使用


具体的需要看CacheManager


@Resource
private CacheManager cacheManager;

@PatchMapping(“/course2/{id}”)
public Course course2(@PathVariable Integer id) {
// 获取指定命名空间的cache
Cache cache = cacheManager.getCache(“course”);
// 通过key获取对应的value
Cache.ValueWrapper wrapper = cache.get(2);
if (wrapper == null) {
// 查询数据库
Course course = courseService.getCourseInfo(id);
// 加入缓存
cache.put(course.getId(), course);
return course;
} else {
// 将缓存的结果返回
// 因为配置了enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// 所以在进行强转的时候不会报错
return (Course) wrapper.get();
}
}