32.4 JCache (JSR-107) 注解
Spring Framework 4.1 以来,缓存抽象完全支持 JCache 标准:即 @CacheResult
,@CachePut
,@CacheRemove
和 @CacheRemoveAll
还有 @CacheDefaults
,@CacheKey
和 @CacheValue
。这些注解被大家正确的使用,体现了缓存在 JSR-107
的实现:缓存抽象的内部实现,并提供了符合规范的默认 CacheResolver
和 KeyGenerator
的实现。换句话说,如果你已经使用了 Spring 缓存抽象,那可以平滑切换到这些标准注解,无需更改缓存存储(或者配置)。
32.4.1 特征总结
对于熟悉 Spring 缓存注解,下面描述了 Spring 注解和 JSR-107 对应的主要区别:
表 32.3. Spring vs 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 只支持单个缓存。默认下,根据注解声明的名称检索要使用的缓存。如果没有指定缓存的名称,则会自动生成默认值。更多信息可以查看 javadoc 的 @CacheResult#cacheName()
。
CacheResolverFactory
检索出 CacheResolver
实例。每个缓存操作都可以自定义工厂:
@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class)
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 管理注解方法抛出的异常:可以防止缓存更新,但将异常作为故障的标志,而不是再次调用该方法。假设抛出 InvalidIsbnNotFoundException 异常,那么 ISBN 的结构是无效的。如果这是一个永久的失败,没有任何书会被查询出来。以下的缓存异常,以使具有无效的 ISBN 进一步直接抛出缓存的异常,而不是再次调用该方法。
@CacheResult(cacheName="books", exceptionCacheName="failures"
cachedExceptions = InvalidIsbnNotFoundException.class)
public Book findBook(ISBN isbn)
32.4.2 启用 JSR-107 支持
不需要特殊处理,去支持 JSR-107 和 Spring 的声明式注解。JSR-17 API 和 spring-context-support
模块在类路径下,@EnableCaching
和 cache:annotation-driven
两者会被启用。
根据你的具体案例选择需要的。你还可以使用 JSR-107 API 和其他使用 Spring 自己的注解来匹配服务。注意,如果这些服务影响相同的缓存,则使用一致的键生成实现。