对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

JCache (JSR-107) 注解

从版本 4.1 开始,Spring 的缓存抽象完全支持 JCache 标准(JSR-107)注解: @CacheResult@CachePut@CacheRemove@CacheRemoveAll,以及 @CacheDefaults@CacheKey@CacheValue 的配套注解。 即使没有将缓存存储迁移到 JSR-107,也可以使用这些注解。 内部实现使用 Spring 的缓存抽象,并提供了符合规范的默认 CacheResolverKeyGenerator 实现。换句话说,如果您已经在使用 Spring 的缓存抽象,可以切换到这些标准注解,而无需更改您的缓存存储(或配置)。spring-doc.cadn.net.cn

功能摘要

对于熟悉 Spring 缓存注解的用户,下表描述了 Spring 注解与其 JSR-107 对应项之间的主要区别:spring-doc.cadn.net.cn

表 1. Spring 与 JSR-107 缓存注解
Spring JSR-107 备注

@Cacheablespring-doc.cadn.net.cn

@CacheResultspring-doc.cadn.net.cn

相当类似。@CacheResult 可以缓存特定的异常并强制执行该方法,无论缓存中的内容如何。spring-doc.cadn.net.cn

@CachePutspring-doc.cadn.net.cn

@CachePutspring-doc.cadn.net.cn

当Spring在方法调用结果的基础上更新缓存时,JCache要求将其作为带有@CacheValue注解的参数传递。 由于这一差异,JCache允许在实际方法调用之前或之后更新缓存。spring-doc.cadn.net.cn

@CacheEvictspring-doc.cadn.net.cn

@CacheRemovespring-doc.cadn.net.cn

相当类似。 @CacheRemove 在方法调用导致异常时支持条件性逐出。spring-doc.cadn.net.cn

@CacheEvict(allEntries=true)spring-doc.cadn.net.cn

@CacheRemoveAllspring-doc.cadn.net.cn

查看 @CacheRemovespring-doc.cadn.net.cn

@CacheConfigspring-doc.cadn.net.cn

@CacheDefaultsspring-doc.cadn.net.cn

让你以类似的方式配置相同的概念。spring-doc.cadn.net.cn

JCache 有 javax.cache.annotation.CacheResolver 的概念,这与 Spring 的 CacheResolver 接口相同,只是 JCache 仅支持一个缓存。默认情况下,一个简单实现会根据注解上声明的名称来获取要使用的缓存。需要注意的是,如果注解上没有指定缓存名称,将自动生成一个默认值。有关更多信息,请参阅 @CacheResult#cacheName() 的 javadoc。spring-doc.cadn.net.cn

CacheResolver 个实例由 CacheResolverFactory 检索。可以为每个缓存操作自定义工厂,如下例所示:spring-doc.cadn.net.cn

@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) (1)
public Book findBook(ISBN isbn)
1 为该操作自定义工厂。
对于所有引用的类,Spring 会尝试查找具有给定类型的 bean。 如果存在多个匹配项,将创建一个新实例,并可以使用常规的 bean 生命周期回调,例如依赖注入。

键由一个 javax.cache.annotation.CacheKeyGenerator 生成,其作用与 Spring 的 KeyGenerator 相同。默认情况下,所有方法参数都会被考虑在内,除非至少有一个参数使用 @CacheKey 进行了注解。这类似于 Spring 的 自定义键生成声明。例如,以下两个操作是相同的,一个使用 Spring 的抽象,另一个使用 JCache:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@CacheResult(cacheName="books")
public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse, boolean includeUsed)

你也可以在操作中指定 CacheKeyResolver,类似于如何指定 CacheResolverFactoryspring-doc.cadn.net.cn

JCache可以管理由注释方法抛出的异常。这可以防止缓存的更新,但也可以将异常缓存起来作为失败的指示,而不是再次调用该方法。假设当ISBN的结构无效时会抛出InvalidIsbnNotFoundException。这是一个永久性错误(使用这样的参数永远无法检索到书籍)。以下代码将异常缓存起来,这样后续使用相同且无效的ISBN进行调用时会直接抛出缓存的异常,而不是再次调用该方法:spring-doc.cadn.net.cn

@CacheResult(cacheName="books", exceptionCacheName="failures"
			cachedExceptions = InvalidIsbnNotFoundException.class)
public Book findBook(ISBN isbn)

启用 JSR-107 支持

您无需执行任何特定操作即可在Spring的声明式注解支持的同时启用JSR-107支持。如果类路径中同时存在JSR-107 API和spring-context-support模块,则@EnableCachingcache:annotation-driven XML元素会自动启用JCache支持。spring-doc.cadn.net.cn

根据您的使用场景,选择基本上是您自己的。您甚至可以混合使用服务,对某些服务使用 JSR-107 API,而对其他服务使用 Spring 自己的注解。然而,如果这些服务影响相同的缓存,您应该使用一致且相同的键生成实现。