JCache (JSR-107) 注解
从 4.1 版本开始,Spring 的缓存抽象完全支持 JCache 标准(JSR-107)注解:@CacheResult
、@CachePut
、@CacheRemove
和 @CacheRemoveAll
,以及 @CacheDefaults
、@CacheKey
和 @CacheValue
辅助注解。即使不将缓存存储迁移到 JSR-107,你也可以使用这些注解。内部实现使用 Spring 的缓存抽象,并提供符合规范的默认 CacheResolver
和 KeyGenerator
实现。换句话说,如果你已经在使用 Spring 的缓存抽象,可以切换到这些标准注解,而无需更改缓存存储(或配置)。
功能摘要
对于熟悉 Spring 缓存注解的人来说,下表描述了 Spring 注解与其 JSR-107 对应注解之间的主要区别:
表 1. Spring 与 JSR-107 缓存注解对比
Spring | JSR-107 | 备注 |
---|---|---|
@Cacheable | @CacheResult | 相当相似。@CacheResult 可以缓存特定异常,并强制执行方法而不考虑缓存的内容。 |
@CachePut | @CachePut | 当 Spring 使用方法调用的结果更新缓存时,JCache 要求将其作为带有 @CacheValue 注解的参数传递。由于此差异,JCache 允许在实际方法调用之前或之后更新缓存。 |
@CacheEvict | @CacheRemove | 相当相似。@CacheRemove 支持在方法调用导致异常时进行条件性清除。 |
@CacheEvict(allEntries=true) | @CacheRemoveAll | 参见 @CacheRemove 。 |
@CacheConfig | @CacheDefaults | 允许以类似的方式配置相同的概念。 |
JCache 具有 javax.cache.annotation.CacheResolver
的概念,这与 Spring 的 CacheResolver
接口相同,只是 JCache 仅支持单个缓存。默认情况下,一个简单的实现会根据注解上声明的名称来检索要使用的缓存。需要注意的是,如果注解上没有指定缓存名称,则会自动生成一个默认名称。有关更多信息,请参阅 @CacheResult#cacheName()
的 javadoc。
CacheResolver
实例由 CacheResolverFactory
获取。可以为每个缓存操作自定义工厂,如以下示例所示:
@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) 1
public Book findBook(ISBN isbn)
为此操作定制工厂。
对于所有引用的类,Spring 会尝试定位具有给定类型的 bean。如果存在多个匹配项,则会创建一个新实例,并可以使用常规的 bean 生命周期回调,例如依赖注入。
键是由 javax.cache.annotation.CacheKeyGenerator
生成的,其作用与 Spring 的 KeyGenerator
相同。默认情况下,所有方法参数都会被考虑,除非至少有一个参数被注解为 @CacheKey
。这与 Spring 的自定义键生成声明类似。例如,以下是相同的操作,一个使用 Spring 的抽象,另一个使用 JCache:
@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
,这与指定 CacheResolverFactory
的方式类似。
JCache 可以管理被注解方法抛出的异常。这可以阻止缓存的更新,但它也可以将异常缓存为失败的指示器,而不是再次调用该方法。假设如果 ISBN 的结构无效,则抛出 InvalidIsbnNotFoundException
。这是一个永久性失败(没有书籍可以用这样的参数检索到)。以下内容缓存异常,以便对相同无效 ISBN 的进一步调用直接抛出缓存的异常,而不是再次调用该方法:
@CacheResult(cacheName="books", exceptionCacheName="failures"
cachedExceptions = InvalidIsbnNotFoundException.class)
public Book findBook(ISBN isbn)
启用 JSR-107 支持
您无需执行任何特定操作即可在 Spring 的声明性注解支持下启用 JSR-107 支持。如果类路径中同时存在 JSR-107 API 和 spring-context-support
模块,那么 @EnableCaching
和 cache:annotation-driven
XML 元素会自动启用 JCache 支持。
根据您的使用案例,选择基本上取决于您。您甚至可以通过在某些服务上使用 JSR-107 API,并在其他服务上使用 Spring 自己的注解来混合和匹配服务。但是,如果这些服务影响相同的缓存,您应该使用一致且相同的键生成实现。