在获取数据库数据或者其他IO成本高的数据时,缓存很有必要。目前内存缓存常用的有Ehcache,Guava cache 等。
Ehcache是springframework中提供的缓存解决方案。用EhCache可以轻松实现对某些资源的内存缓存,并进行定时更新及手动更新。
Spring与EhCache结合,通过注解的方式即可简单实现某个方法返回值的缓存。
EhCache的接入过程如下:
- pom中添加依赖:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
- 在classpath下增加ehcache配置文件 ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
<diskStore path="java.io.tmpdir"/>
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。
仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。
仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts
of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。
默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="someDOCache" maxElementsInMemory="10000" eternal="false"
timeToLiveSeconds="1800" overflowToDisk="false" diskPersistent="false" />
</ehcache>
- spring配置文件 applicationContext.xml ,增加cache相关的xmlns和xsi
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- ehcache -->
<cache:annotation-driven cache-manager="ehcacheManager"/>
<!-- 声明cacheManager -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManagerFactory" />
</bean>
<!-- cacheManager工厂类,指定ehcache.xml的位置 -->
<bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:util/ehcache.xml" />
</bean>
- 在想要将结果缓存的方法上加注解@Cacheable即可
//此方法的返回值将进入someDOCache缓存起来,key为allRules
@Cacheable(value = "someDOCache", key = "'allRules'")
public List<someDO> getAllData() {
//从数据库获取某数据
}
//此方法清除指定key下的缓存内容,以便下次重新加载
@CacheEvict(value = "someDOCache",key = "'allRules'")
public void updateAllData() {
}
//key可以用入参拼接,如下(缓存了“hello{id}的字符串)
@Cacheable(value = "dbCache",key = "'getMsg_' + #id")
public String getMsg(String id) {
LOG.info("cache Msg(id) by " + id);
return "hello " + id;
}
@CacheEvict(value = "dbCache",key = "'getMsg_' + #id")
public void updateMsg(String id) {
LOG.info("updateMsg by id " + id);
}
//此外,可以指定condition,只有满足条件才会cache或evict
@Cacheable(value = "QY_api_productTop",key="#isbn.id",condition = "#isbn.id<10")
public Manual findManual(ISBN isbn, boolean checkWarehouse)
- 注解详情
@Cacheable:负责将方法的返回值加入到缓存中
@CacheEvict:负责清除缓存
@Cacheable 支持如下几个参数:
value:缓存位置名称,不能为空,即ehcache.xml中声明的cache name
key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL
condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
@CacheEvict 支持如下几个参数:
value:缓存位置名称,不能为空,同上
key:缓存的key,默认为空,同上
condition:触发条件,只有满足条件的情况才会清除缓存,默认为空,支持SpEL
allEntries:true表示清除value中的全部缓存,默认为false
一般来说,我们的更新操作只需要刷新缓存中某一个值,所以定义缓存的key值的方式就很重要,最好是能够唯一,因为这样可以准确的清除掉特定的缓存,而不会影响到其它缓存值。
参考链接:
my.oschina.net/lemonzone20…
qincidong.github.io/blog/2015/0…