生效原理
抽象而不是实现
Spring框架中, 缓存服务是一组抽象, 也就是一组API, 由
org.springframework.cache.Cache
org.springframework.cache.CacheManager
抽象. 抽象中并不包含多线程或者多进程处理逻辑, 这些逻辑应该由缓存实现方提供. Spring data工程默认提供了一些实现, 例如ConcurrentHashMap
, GemFire, Ehcache等.
通过在方法级别上加@Cacheable
等注解, 每当方法被调用的时候, Spring通过AOP的方式拦截方法的执行, 执行缓存的添加, 更新, 删除等操作(取决于注解属性的配置和注解类型).
声明式缓存
在Spring中使用缓存的方式是声明式缓存, 只需要三步配置即可启用:
- 缓存声明
在需要缓存的方法上以注解的形式标识. - 缓存配置
显式或隐式配置缓存数据存储后端(Redis, ConcurrentHashMap等). - 在
@Configuration
配置类中加上@EnableCaching
, 在应用范围内启用注解.
声明式缓存的类型
共有以下类型:
@Cacheable
查询缓存@CacheEvict
删除缓存条目@CachePut
更新缓存条目@Caching
@CacheConfig
三级缓存策略定制
从上到下, 依次可以进行三次缓存策略的设定, 每一层都会覆盖上层的默认设定:
- 全局范围的定制: 配置在
CacheManager
和KeyGenerator
中. - 类级别的定制: 使用
@CacheConfig
注解; - 方法级别的定制.
Key生成策略
说到底最终还是要以key-value的形式写到后端存储中, 那么Spring的Key生成策略就是值得考虑的. Spring默认的KeyGenerator
使用以下算法:
- 如果没有参数, 返回
SimpleKey.EMPTY
- 如果只有一个参数, 直接返回参数实例.
- 如果有多个参数, 那么返回一个包含所有参数的
SimpleKey
.
那么也就是说, 对于cacheNames
相同的方法, 如果他们调用时的参数类型和值也相同, 那么就会认为使用的是同一条缓存条目:
@Cacheable(cacheNames = "girl")
public Girl findOne(Integer id) {
logger.error("方法findOne被调用!");
return girlRepository.findOne(id);
}
@Cacheable(cacheNames &#