1.Spring 缓存介绍
1.1 Spring 缓存简介
Spring 提供了对缓存功能的抽象:即允许绑定不同的缓存解决方案(如Ehcache),但本身不直接提供缓存功能的实现。它支持注解方式使用缓存,非常方便。
1.2 缓存管理器
Spring 3.1内置了五个缓存管理器实现,如下所示:
- SimpleCacheManager
- NoOpCacheManager
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhCacheCacheManagerSpring 3.2引入了另外一个缓存管理器,这个管理器可以用在基于JCach e(JSR-107)的缓存提供商之中。除了核心的Spring框架,Spring Data又提供了两个缓存管理器:
- RedisCacheManager(来自于Spring Data Redis项目)
- GemfireCacheManager(来自于Spring Data GemFire项目)
2. Spring 缓存使用
2.1 注解方式
@Cacheable
说明: 表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中
@CachePut
说明: 表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用
参数 | 作用 | 例 (@Cacheable和@CachePut) |
---|---|---|
value | 缓存的名称,在spring 配置文件中定义,必须指定至少一个 | @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的key,可以为空,如果指定要按照SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用SpEL编写,返回true或者false只有为true才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | SpEL表达式,可以为空,如果得到的值是true的话,返回值不会放到缓存之中 |
@CacheEvict
说明: 表明Spring应该在缓存中清除一个或多个条目
参数 | 作用 | 例 @CacheEvict) |
---|---|---|
value | 缓存的名称,在spring 配置文件中定义,必须指定至少一个 | @CacheEvict(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的key,可以为空,如果指定要按照SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @CachEvict(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 | @CachEvict(value=”testcache”,condition=”#userName.length()>2”) |
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value=”testcache”,beforeInvocation=true) |
@Caching
说明: 使用同一个缓存注解多次修饰一个方法.
例:
@CacheConfig
说明: 与前面的缓存注解不同,这是一个类级别的注解。如果类的所有操作都是缓存操作,你可以使用@CacheConfig来指定类,省去一些配置。
例:
SpEL扩展
Spring提供了多个用来定义缓存规则的SpEL扩展
属性名称 | 描述 | 表达式 |
---|---|---|
methodName | 当前方法名 | `#root.methodName |
method | 当前方法 | `#root.method.name |
target | 当前被调用的对象 | `#root.target |
targetClass | 当前被调用的对象的class | `#root.targetClass |
args | 当前方法参数组成的数组 | `#root.args[0] |
caches | 当前被调用的方法使用的Cache | `#root.caches[0].name |
方法调用的返回值(不能用在@Cacheable注解上) | `#result | |
任意的方法参数名(如#argName)或参数索引(如#a0或#p0) | `#Argument |
3.Spring配置Ehcache缓存
3.1 Ehcache缓存简介
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。它是Hibernate中的默认缓存框架。
- 主要的特性有:
1. 快速
2. 简单
3. 多种缓存策略
4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题
5. 缓存数据会在虚拟机重启的过程中写入磁盘
6. 可以通过RMI、可插入API等方式进行分布式缓存
7. 具有缓存和缓存管理器的侦听接口
8. 支持多缓存管理器实例,以及一个实例的多个缓存区域
9. 提供Hibernate的缓存实现
3.2 配置Ehcache缓存
第一步: maven 依赖添加
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>${ehcache.version}</version> </dependency> <!-- 这个jar包中含有Spring对于缓存功能的抽象封装接口。--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency>
第二步: applicationContext.xml 配置
<!-- 在spring.xml的配置文件中引入schema --> xmxmlns:cache="http://www.springframework.org/schema/cache" http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 --> <cache:annotation-driven cache-manager="ehcacheManager"/> <!-- 声明Ehcache缓存管理器 --> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcacheManagerFactory" /> </bean> <!-- 加载Ehcache配置 --> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> </bean>
第三步: 配置ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <!-- 磁盘缓存位置 --> <diskStore path="java.io.tmpdir"/> <!-- 默认缓存 --> <defaultCache maxEntriesLocalHeap="10000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> <!-- 自定义缓存 --> <cache name="myCache" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="30" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap"/> </cache> </ehcache>
3.3 Ehcache 配置参数介绍
参数 | 含义 |
---|---|
< diskStore> | 当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口) |
< diskStore path=”“> | 用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是.data和.index |
name | “缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里) |
maxEntriesLocalHeap=”1000” | 堆内存中最大缓存对象数,0没有限制(必须设置) |
maxEntriesLocalDisk=”1000” | 磁盘缓存中最多可以存放的元素数量,0表示无穷大 |
maxElementsInMemory | 内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况:1.若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中. 2.若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素 |
overflowToDisk=”false” | 内存不足时,是否启用磁盘缓存(即内存中对象数量达到maxElementsInMemory时,Ehcache会将对象写到磁盘中) , 会根据标签中path值查找对应的属性值,写入磁盘的文件会放在path文件夹下,文件的名称是cache的名称,后缀名是data |
memoryStoreEvictionPolicy=”LFU” | 内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存.共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出) |
eternal=”false” | 缓存中对象是否永久有效,即是否永驻内存,true时将忽略timeToIdleSeconds和timeToLiveSeconds(必须设置) |
timeToIdleSeconds=”0” | 缓存数据在失效前的允许闲置时间(单位:秒),仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,此为可选属性 即访问这个cache中元素的最大间隔时间,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除 |
timeToLiveSeconds=”600” | 缓存数据在失效前的允许存活时间(单位:秒),仅当eternal=false时使用,默认值是0表示可存活时间无穷大即Cache中的某元素从创建到清楚的生存时间,也就是说从创建开始计时,当超过这个时间时,此元素将从Cache中清除 |
diskPersistent=”false” | 磁盘缓存在JVM重新启动时是否保持(默认为false) ,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件 这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存 要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法 |
clearOnFlush | 内存数量最大时是否清除 |
diskExpiryThreadIntervalSeconds | 磁盘失效线程运行时间间隔,默认是120秒 |
diskSpoolBufferSizeMB | 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 |
3.4 注意事项
- 要实现缓存的实体必须要序列化