spring 缓存机制
简介
Spring3.1开始引入了基于注释的缓存,其使用方法和原理类似于Spring对事务管理的支持。可以对容器中的任意的bean或bean的方法添加缓存。
配置Spring缓存
Spring缓存主要有三个配置
1.在Spring配置文件导入context:命名空间
2.配置缓存管理器,不同的缓存使用不同的配置,如果是EhCache,需要先配置一个ehcache.xml
3.在spring配置文件中启用缓存,如下:
<cache:annotation-driven cache-manager="缓存管理器ID" />
ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir"/> <!-- 默认缓存区 --> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"/> <!-- 名为quoteCarrier的缓存区 --> <cache name="users" maxElementsInMemory="100" eternal="true" overflowToDisk="true"/> </ehcache>
参数说明:
参数 | 说明 |
---|---|
<diskStore/> |
当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口)。 |
<diskStore path=""/> |
用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是.data和.index。 |
name | 缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里)。 |
maxElementsOnDisk | 磁盘缓存中最多可以存放的元素数量,0表示无穷大。 |
maxElementsInMemory | 内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况:(1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中。(2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素。 |
Eternal | 缓存中对象是否永久有效,即是否永驻内存,true时将忽略timeToIdleSeconds和timeToLiveSeconds。 |
timeToIdleSeconds | 缓存数据在失效前的允许闲置时间(单位:秒),即访问这个cache中元素的最大间隔时间,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除。默认值是0表示可闲置时间无穷大。仅当eternal=false时使用 |
timeToLiveSeconds | 缓存数据在失效前的允许存活时间(单位:秒),即Cache中的某元素从创建到清除的生存时间,也就是说从创建开始计时,当超过这个时间时,此元素将从Cache中清除。默认值是0表示可闲置时间无穷大。仅当eternal=false时使用 |
overflowToDisk | 内存不足时,是否启用磁盘缓存(即内存中对象数量达到maxElementsInMemory时,Ehcache会将对象写到磁盘中) |
diskPersistent | 是否持久化磁盘缓存。当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法。 |
diskExpiryThreadIntervalSeconds | 磁盘缓存的清理线程运行间隔,默认是120秒。 |
diskSpoolBufferSizeMB | 设置DiskStore(磁盘缓存)的缓存区大小,默认是30MB |
memoryStoreEvictionPolicy | 内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存,共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出)。 |
配置缓存管理器
看一个完整的Spring配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.service"/> <!-- 启用缓存 --> <cache:annotation-driven cache-manager="cacheManager" /> <!-- 配置EhCache的CacheManager,通过configLocation指定ehcache.xml文件的位置 --> <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml" p:shared="false" /> <!-- 配置基于EhCache的缓存管理器,并将EhCache的CacheManager注入该缓存管理器Bean --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehCacheManager" > </bean> </beans>
这样就可以在java文件里启用缓存注解了。
@Service("userService") @Cacheable(value="users") public class UserServiceImpl implements UserService { @Override public User getUsersByNameAndAge(String name, int age) { System.out.println("正在执行getUsersByNameAndAge().."); return new User(name,age); } }
当然,注解也可以加在某个方法上,如:
@Service("userService") public class UserServiceImpl implements UserService { @Override @Cacheable(value = "users", key = "#name", sync = true) public User getUsersByNameAndAge(String name, int age) { System.out.println("正在执行getUsersByNameAndAge().."); return new User(name,age); } }
基于类或某个方法的缓存,缓存之后,程序调用该类或该方法,只要传入的参数相同,Spring并不会真正进入该类或方法,而是直接根据传入的参数去缓存中查找数据。
Spring基于注解的缓存
1.@Cacheable
该注解主要针对方法注释,能够根据方法的请求参数对其结果进行缓存。
主要参数有:
参数 | 说明 | 例子 |
---|---|---|
value | 缓存的名称,在 pring配置文件中定义,必须指定至少一个 | @Cacheable(value="users")或@Cacheable(value={"cache1","cache2"} |
key | 缓存的key,可以为空,如果指定要按照SpEL表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value="users",key="#userName") |
condition | 缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存 | @Cacheable(value="menuCache",condition="#userName.length()>2") |
2.@CachePut
主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用。也就是说,用@CachePut标注的方法在执行前都不会去检查缓存中是否存在之前执行过的结果,而是在每次执行时都会调用该方法,将该方法的结果以键值对的形式存入指定的缓存中。
那么既然每次cachePut都要触发真实的方法调用,那么它的作用是什么呢?
看一段代码:
@Cacheable(value="userCache",key="1000") public String getUserByName(String userName) { System.out.println("两次调用第一次会执行,第二次不会执行!"); return getFromDB(userName); } @CachePut(value="userCache",key="1000") public String updateUserPut(String userName) { return updateDB(userName); }
在进行数据库相关的操作时,如果是要更新数据,那么使用@CachePut可以确保每次更新的数据都写进了缓存里,那么下次再获取相同的数据的时候,就能拿到更新后的数据。这里只要保证:
(1)必须是同一个缓存实例
(2)必须是相同的key
@CachePut的参数跟@Cacheable是一样的,参考@Cacheable的参数即可。
3.@CachEvict
主要针对方法配置,能够根据一定的条件对缓存进行清空。
除了value, key, condition这三个基本参数之外,还有其他参数:
参数 | 说明 |
---|---|
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 |