缓存-Spring Cache 缓存抽象

缓存-Spring Cache 缓存抽象

Spring从版本3.1开始提供非侵入的将Cache集成到Spring应用的方式。Spring Cache提供Cache的统一抽象,支持集成各种不同的缓存解决方案。从4.1版本开始,提供了注解和更多的定制参数。

Spring Cache 抽象提供了对Java方法的缓存,使用Spring Cache缓存,当方法调用使用相同的参数,调用结果被缓存下来,当方法被再次调用时将直接返回参数结果。

关键类和接口

Cache

org.springframework.cache.Cache 提供Spring框架中使用的Cache的统一抽象功能, 具体的实现类使用实际的缓存解决方案。

  • NoOpCache: 空缓存,没有实际的缓存实现
  • EhCacheCache: 使用EhCache缓存方案。
  • CaffeineCache: 使用Java CaffeineCache。Caffeine提出了一种更高效的近似LFU准入策略的缓存结构TinyLFU及其变种W-TinyLFU,借鉴Guava Cache的设计经验,是一款功能强大,性能更优本地缓存。
  • JCacheCache: Javax Cache 标准接口,类似于Spring Cache的 JavaJ JSR缓存规范。
  • ConcurrentMapCache: 使用ConccrentMap的缓存实现。
  • TransactionAwareCacheDecorator: 识别Spring 事务的缓存实现装饰模式,只要当事务提交时才触发缓存的更新。

CacheManager

org.springframework.cache.CacheManager:Spring cache 管理API。不同的CacheManager实现提供对相应Cache实现缓存的管理,通过管理API Cache getCache(String name);方法对外提供。

CacheResolver

org.springframework.cache.interceptor.CacheResolver 方法调用拦截使用来获取Cache实现的Resolver,通常使用相应的CacheManager实现类来获取Cache。

KeyGenerator

org.springframework.cache.interceptor. KeyGenerator:缓存中Key的生成实现。默认的key生成器:org.springframework.cache.interceptor.SimpleKeyGenerator 类

  1. 方法没有参数则使用SimpleKey.EMPTY

  2. 方法只有一个参数:key=唯一参数

  3. 方法有多个参数:SimpleKey(params)

可以通过实现org.springframework.cache.interceptor.KeyGenerator接口定制key生成器。

使用Spring Cache

启用Spring Cache

@Configuration

@EnableCaching

注解使用

**@Cacheable:**作用于方法之上,配置方法缓存

@Cacheable("cacheName"): 指定用于缓存结果的缓存名称,当指定多个名称时,方法调用将在多个缓存中查找相同参数的方法调用,命中即返回。

Cache 的key

指定KeyGenerator:

@Cacheable(cacheNames="XXX", keyGenerator="myKeyGenerator")。

通过SpEL指定key

@Cacheable(cacheNames="books", key="#isbn")

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@CachePut: @CachePut指定的方法不影响方法的执行,方法执行结果将用于更新缓存。@CachePut支持同@Cacheable一样的配置。

示例:

@CachePut(cacheNames="book", key="#isbn")

public Book updateBook(ISBN isbn, BookDescriptor descriptor)

**@CacheEvict:**触发缓存清理陈旧或无用的数据。可以配置指定数据的清理或Cache范围的清理。

示例:

@CacheEvict(cacheNames="books", allEntries=true)

public void loadBooks(InputStream batch)

@Caching: 在一个方法上指定触发缓存的多个操作。

示例:

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })

public Book importBooks(String deposit, Date date)

**@CacheConfig:**以上的注解都是方法级别的注解,@CacheConfig提供类级别的公共配置,该类下的方法级别配置如无指定则使用类级别上的@CacheConfig。

实现方式

Spring AOP

使用 Spring AOP切面实现Cache相关方法的拦截获取缓存和Cache请求的处理

  1. 配置切面: 所有所有类和所有方法都进行拦截

org.springframework.cache.interceptor.CacheProxyFactoryBean

相关代码:

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| private Pointcut pointcut = Pointcut.TRUE; protected Object createMainInterceptor() { this.cacheInterceptor.afterPropertiesSet(); return new DefaultPointcutAdvisor(this.pointcut, this.cacheInterceptor); } |

  1. org.springframework.cache.interceptor.CacheInterceptor 实现

org.springframework.cache.interceptor.MethodInterceptor接口,

CacheAspectSupport.execute方法是Spring Cache核心处理流程,下面是主要流程的部分代码解析:

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 处理CacheEvict请求 processCacheEvicts(contexts.get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT); // 从缓存中查询是否存在缓存 Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class)); // 如未命中,生成CachePut请求:缓存条件满足 List<CachePutRequest> cachePutRequests = new ArrayList<>(); if (cacheHit == null) { collectPutRequests(contexts.get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests); } Object cacheValue; Object returnValue; if (cacheHit != null && !hasCachePut(contexts)) { // 缓存命中,并且没有Put需求,返回缓存值 cacheValue = cacheHit.get(); returnValue = wrapCacheValue(method, cacheValue); } else { // 未命中,调用对象,获取可缓存值 returnValue = invokeOperation(invoker); cacheValue = unwrapReturnValue(returnValue); } // 检查是否存在CachePut请求 collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests); // 缓存更新 for (CachePutRequest cachePutRequest : cachePutRequests) { cachePutRequest.apply(cacheValue); } // 处理缓存Evicts请求 rocessCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue); return returnValue; } |

相关推荐
reiraoy4 分钟前
缓存解决方案
java
安之若素^19 分钟前
启用不安全的HTTP方法
java·开发语言
魔芋红茶24 分钟前
spring-initializer
python·学习·spring
ruanjiananquan9925 分钟前
c,c++语言的栈内存、堆内存及任意读写内存
java·c语言·c++
chuanauc1 小时前
Kubernets K8s 学习
java·学习·kubernetes
一头生产的驴1 小时前
java整合itext pdf实现自定义PDF文件格式导出
java·spring boot·pdf·itextpdf
YuTaoShao1 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
zzywxc7871 小时前
AI 正在深度重构软件开发的底层逻辑和全生命周期,从技术演进、流程重构和未来趋势三个维度进行系统性分析
java·大数据·开发语言·人工智能·spring
YuTaoShao4 小时前
【LeetCode 热题 100】56. 合并区间——排序+遍历
java·算法·leetcode·职场和发展
程序员张34 小时前
SpringBoot计时一次请求耗时
java·spring boot·后端