1.Jcache(JSR-107) 注解
从4.1以后,Spring的缓存抽象完全支持Jcache 的注解:@CacheResult,@CachePut,@CacheRemove,和@CacheRemoveAll 以及@CacheDefaults, @CacheKey, and @CacheValue配合使用.即使不用做任何前移也能通过使用这些注解来使用JSR-107. SPring内部使用缓存抽象提供的默认 CacheResolver和KeyGenerator 都符合规范。所以不需要修改缓存存储就可以切换到这些标准的注解.
1.1特点总结
Spring vs. JSR-107 caching annotations
Spring | JSR-107 | Remark |
@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 相同,除了它只支持一个单一缓存. 默认情况下,一个简单的检索缓存的实现是通过声明在注解上的名字.注意的是如果注解上没有缓存名字,会默认自动生成. 细节再@CacheResult#cacheName()文档中
CacheResolver的实例时被CacheResolverFactor 检索到的.可以如下自定义给每个缓存操作
@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) public Book findBook(ISBN isbn) |
为操作定义工厂.
对于所有的引用类,Spring会根据给定类型来定位bean.如果超过一个,就会创建一个新的实例,并且使用常规的bean的生命周期调用,例如依赖注入
通过javax.cache.annotation.CacheKeyGenerator 产生key,与spring的 keyGenerator目的相同.默认所有的方法参数都会使用,除非使用@CacheKey注解.和Spring类似.
1 2 3 4 5 | @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可以管理异常抛出 通过方法注解. 可以防止缓存更新,也可以避免失败的方法被重复调用.
1 2 3 | @CacheResult(cacheName="books", exceptionCacheName="failures" cachedExceptions = InvalidIsbnNotFoundException.class) public Book findBook(ISBN isbn) |
1.2启用 JSR-107的支持
不需要坐任何其他的事情来启用JSR-107,通过 @EnableCaching就可以使用
基于实际场景,选则怎么使用注解,即使混用JSR-107和spring自带的注解也是可以的.然而,如果这些服务影响了相同的缓存,最好还是保证 key生成的一致性.
2.配置缓存的存储
缓存抽象提供了多种存储集成选项.需要自己声明一个合适的 CacheManager.
2.1 JDK-ConcurrentMap
基于JDK的缓存在 org.springframework.cache.concurrent包下. 我们使用ConcurrentHashMap 来作为后备缓存.
1 2 3 4 5 6 7 8 9 | <!-- simple cache manager --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/> </set> </property> </bean> |
上面使用SimpleCacheManage 来配置两个ConcurrentMapCache, 这个缓存扩展性很好并且很快,但是不提供任何管理,持久化能力,或者驱散的协议.
2.2 基于Ehcache的缓存
Encache 3.* 完全支持JSR-107 ,不需要专门支持他
Encache2.* 实现在包下 org.springframework.cache.ehcache. 需要声明CacheManager
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/> <!-- EhCache library setup --> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/> |
通过Spring IOC来设置encache引导, 之后连接 CacheManager的实现.需要注意的是ehcache的指定配置是读取 ehcache.xml
2.3 Caffeine 缓存
Caffeine是java8重写了Guava的缓存,实现的包在 org.springframework.cache.caffeine .
1 2 | <bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/> |
同样可以显示的提供缓存.
1 2 3 4 5 6 7 8 | <bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"> <property name="caches"> <set> <value>default</value> <value>books</value> </set> </property> </bean> |
Caffeine的CacheManage也支持 自定义Caffeine和CacheLoader . 详见
2.4基于GemFire的缓存
GemFire是一种面向内存,磁盘,弹性可伸缩,高可用,活动(具有内置的基于模式的订阅通知),全局复制的数据库,并提供全功能的边缘缓存。有关如何将GemFire用作CacheManager(的更多信息,请参阅 Spring Data GemFire参考文档
2.5 JSR-07缓存
Spring的缓存抽象也可以使用符合JSR-107的缓存。JCache实现位于org.springframework.cache.jcache包中。
同样,要使用它,您需要声明适当的CacheManager。以下示例显示了如何执行此操作:
1 2 3 4 5 6 | <bean id="cacheManager" class="org.springframework.cache.jcache.JCacheCacheManager" p:cache-manager-ref="jCacheManager"/> <!-- JSR-107 cache manager setup --> <bean id="jCacheManager" .../> |
2.6 没有辅助存储的情况下处理缓存
有时,需要一个不执行缓存的简单虚拟缓存,用于测试或者切换环境
1 2 3 4 5 6 7 8 9 | <bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager"> <property name="cacheManagers"> <list> <ref bean="jdkCache"/> <ref bean="gemfireCache"/> </list> </property> <property name="fallbackToNoOpCache" value="true"/> </bean> |
CompositeCacheManager 链接了多个CacheManager实例,通过 fallbackToNoOpCache来配置添加一个 无操作的缓存.也就是说如果 jdkCache或者gemfireCache没有找到相关配置的话会用 误操作缓存处理,这个缓存啥也不做 每次都会调用方法.
3.设置TTL/TTI/Eviction策略
缓存抽象没有实现,你得自己搞