Spring Cache
2019-01-17 本文已影响0人
Minato666
在我们日常编码中,cache是很常见的,在没有使用spring cache之前,我们可能会使用下面这种代码来实现cache:
public class MyCacheManager<T> {
private Map<String,T> cache =
new ConcurrentHashMap<String,T>();
public T getValue(Object key) {
return cache.get(key);
}
public void addOrUpdateCache(String key,T value) {
cache.put(key, value);
}
public void evictCache(String key) {// 根据 key 来删除缓存中的一条记录
if(cache.containsKey(key)) {
cache.remove(key);
}
}
public void evictCache() {// 清空缓存中的所有记录
cache.clear();
}
}
然后在使用的地方使用该cacheManage 缓存和获取数据。缺点就是和业务代码耦合度比较高,不灵活,不能灵活切换第三方缓存模块。而如果使用Spring Cahce就可以杜绝这些问题。
Spring Cache使用非常简单,这里我们使用ehcache作为spring cache的cache manager。由于spring 自带的cachemanager不支持缓存定期失效刷新,所以我们采用ehcache。
- 第一步引入jar包
这里列出关键的两个包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.2</version>
</dependency>
- 第二步
applicationContext.xml 中加入下面的配置:
<cache:annotation-driven/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:config-location="classpath:ehcache.xml"
p:shared="true"/>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cache-manager-ref="ehcache"/>
classpath下加入ehcache.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
<!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
<diskStore path="java.io.tmpdir"/>
<cache name="SystemConfigCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="600"
timeToLiveSeconds="700"/>
</ehcache>
注意其中的cache name,这个是我们后面配置要用到的,
eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false。
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性 值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限 期地处于空闲状态
timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有 效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义
- 第三步 编写cache类
package com.oocl.ir4.sps.service.cache;
import com.oocl.ir4.sps.dao.common.SystemConfigDao;
import com.oocl.ir4.sps.entity.common.SystemConfig;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import javax.annotation.Resource;
@CacheConfig(cacheNames = "SystemConfigCache")
public class SystemConfigCache {
@Resource
SystemConfigDao systemConfigDao;
@Cacheable( key = "'SystemConfig_' + #key")
public SystemConfig getConfigByKey(String key) {
System.out.print("read from db ===================================");
return systemConfigDao.findSystemConfigByKey(key);
}
@CacheEvict(allEntries = true)
public void reload() {
}
}
在类上配置了cacheNames,就是之前我们在ehcache.xml配置的。
其中的getConfigByKey 这个方法,我们给它加了一个annotation,@Cacheable 这个就表示我要把该方法的返回值缓存下来,key就是我们指定的格式”SystemConfig_ + 传入的参数key”.
如果我们想清空缓存,可以使用@CacheEvict(allEntries = true) ,也就是代码中reload方法。
运行下面测试:
@Test
public void systemConfig() {
System.out.println("first query");
SystemConfig systemConfig = systemConfigCache.getConfigByKey(EmailConfig.KEY);
System.out.println(JsonUtil.writeValueAsPrettyString(systemConfig));
System.out.println("second query");
SystemConfig systemConfig1 = systemConfigCache.getConfigByKey(EmailConfig.KEY);
System.out.println(JsonUtil.writeValueAsPrettyString(systemConfig1));
}
获得结果:
first query
read from db ===================================
{
"id" : {
"time" : 1547704819000,
"timestamp" : 1547704819,
"date" : 1547704819000,
"new" : false,
"inc" : 493821772,
"machine" : 1078273087,
"timeSecond" : 1547704819
},
"key" : "EMAIL_CONFIG",
"value" : "{\"aliyunEmailDomains\":[\"stp.com\"]}"
}
second query
{
"id" : {
"time" : 1547704819000,
"timestamp" : 1547704819,
"date" : 1547704819000,
"new" : false,
"inc" : 493821772,
"machine" : 1078273087,
"timeSecond" : 1547704819
},
"key" : "EMAIL_CONFIG",
"value" : "{\"aliyunEmailDomains\":[\"stp.com\"]}"
}
可以看到第一次是从DB中获取数据,第二次是从cache中获取数据。