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支持
你不需要采取任何特别的措施来启用JSR-107支持,Spring的声明式注解支持就已经足够了。只要类路径中包含了JSR-107 API和spring-context-support模块,@EnableCaching以及cache:annotation-driven XML元素就会自动启用JCache支持。
根据你的使用场景,选择权基本上在你手中。你甚至可以在某些服务上使用JSR-107 API,在其他服务上使用Spring自带的注解来混合搭配这些服务。然而,如果这些服务影响到相同的缓存,那么你应该使用一致且相同的键生成实现。